Alias support in progress
diff --git a/bundles/org.eclipse.core.resources/.project b/bundles/org.eclipse.core.resources/.project
index 26047c9..fb58441 100644
--- a/bundles/org.eclipse.core.resources/.project
+++ b/bundles/org.eclipse.core.resources/.project
@@ -14,39 +14,6 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
-			<arguments>
-				<dictionary>
-					<key>!{tool_args}</key>
-					<value>-DbuildType=${build_type}</value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_loc}</key>
-					<value>${workspace_loc:/org.eclipse.core.resources/scripts/buildExtraJAR.xml}</value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_dir}</key>
-					<value></value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_refresh}</key>
-					<value>${none}</value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_name}</key>
-					<value>org.eclipse.core.resources extra builder</value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_type}</key>
-					<value>org.eclipse.ui.externaltools.type.ant</value>
-				</dictionary>
-				<dictionary>
-					<key>!{tool_show_log}</key>
-					<value>true</value>
-				</dictionary>
-			</arguments>
-		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.jdt.core.javanature</nature>
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java
index 120433e..421d377 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java
@@ -19,7 +19,7 @@
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
-public class BuildManager implements ICoreConstants, IManager {
+public class BuildManager implements ICoreConstants, IManager, ILifecycleListener {
 	protected Workspace workspace;
 	protected boolean building = false;
 	
@@ -261,10 +261,6 @@
 protected boolean canRun(int trigger) {
 	return !building;
 }
-public void changing(IProject project) {
-}
-public void closing(IProject project) {
-}
 /**
  * Creates and returns a Map mapping String(builder name) -> BuilderPersistentInfo. 
  * The table includes entries for all builders that are
@@ -315,11 +311,6 @@
 		return "<no project>"; //$NON-NLS-1$
 	return currentBuilder.getProject().getFullPath().toString();
 }
-public void deleting(IProject project) {
-	//make sure the builder persistent info is deleted for the project move case
-	if (project.isAccessible())
-		setBuildersPersistentInfo(project, null);
-}
 protected IncrementalProjectBuilder getBuilder(String builderName, IProject project, MultiStatus status) throws CoreException {
 	Hashtable builders = getBuilders(project);
 	IncrementalProjectBuilder result = (IncrementalProjectBuilder) builders.get(builderName);
@@ -412,6 +403,17 @@
 		}
 	};
 }
+public void handleEvent(LifecycleEvent event) {
+	IProject project = null;
+	switch (event.kind) {
+		case LifecycleEvent.PRE_PROJECT_DELETE:
+		case LifecycleEvent.PRE_PROJECT_MOVE:
+			project = (IProject)event.resource;
+			//make sure the builder persistent info is deleted for the project move case
+			if (project.isAccessible())
+				setBuildersPersistentInfo(project, null);
+	}			
+}
 /**
  * Hook for adding trace options and debug information at the start of a build.
  */
@@ -546,8 +548,6 @@
 	}
 	return false;	
 }
-public void opening(IProject project) {
-}
 /**
  * Removes all builders with the given ID from the build spec.
  * Does nothing if there were no such builders in the spec
@@ -598,6 +598,7 @@
 public void shutdown(IProgressMonitor monitor) {
 }
 public void startup(IProgressMonitor monitor) {
+	workspace.addLifecycleListener(this);
 }
 /**
  * Returns a string representation of the given builder.  
@@ -636,4 +637,6 @@
 	}
 	return project.isNatureEnabled(nature);
 }
+
+
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/ILifecycleListener.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/ILifecycleListener.java
new file mode 100644
index 0000000..87fe5b8
--- /dev/null
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/ILifecycleListener.java
@@ -0,0 +1,21 @@
+/**********************************************************************
+ * Copyright (c) 2002 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 - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.core.internal.events;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Interface for clients interested in receiving notification of workspace
+ * lifecycle events.
+ */
+public interface ILifecycleListener {
+	public void handleEvent(LifecycleEvent event) throws CoreException;
+}
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/LifecycleEvent.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/LifecycleEvent.java
new file mode 100644
index 0000000..12d8876
--- /dev/null
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/LifecycleEvent.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2002 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 - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.core.internal.events;
+
+import org.eclipse.core.resources.IResource;
+
+/**
+ * Class used for broadcasting internal workspace lifecycle events.  There is a
+ * singleton instance, so no listener is allowed to keep references to the event
+ * after the notification is finished.
+ */
+public class LifecycleEvent {
+	//constants for kinds of internal workspace lifecycle events
+	public static final int PRE_PROJECT_CLOSE = 0x01;
+	public static final int PRE_PROJECT_DELETE = 0x02;
+	public static final int PRE_PROJECT_OPEN = 0x04;
+	public static final int PRE_PROJECT_MOVE = 0x08;
+	public static final int POST_LINK_CREATE = 0x10;
+	public static final int PRE_LINK_DELETE = 0x20;
+	public static final int PRE_LINK_MOVE = 0x40;
+
+	/**
+	 * The kind of event
+	 */
+	public int kind;
+	/**
+	 * For events that only involve one resource, this is it.  More
+	 * specifically, this is used for all non-move events. For move events, this
+	 * resource represents the source of the move.
+	 */
+	public IResource resource;
+	/**
+	 * For move events, this resource represents the destination of the move.
+	 */
+	public IResource newResource;
+	
+	/**
+	 * The update flags for the event.
+	 */
+	public int updateFlags;
+	
+	private static final LifecycleEvent instance = new LifecycleEvent();
+	private LifecycleEvent() {
+		super();
+	}
+	public LifecycleEvent newEvent(int kind, IResource resource) {
+		this.kind = kind;
+		this.resource = resource;
+		this.newResource = null;
+		this.updateFlags = 0;
+		return this;
+	}
+	public LifecycleEvent newEvent(int kind, IResource oldResource, IResource newResource, int updateFlags) {
+		this.kind = kind;
+		this.resource = oldResource;
+		this.newResource = null;
+		this.updateFlags = 0;
+		return this;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/NotificationManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/NotificationManager.java
index d9c4bcf..2db4929 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/NotificationManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/NotificationManager.java
@@ -17,7 +17,7 @@
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
-public class NotificationManager implements IManager {
+public class NotificationManager implements IManager, ILifecycleListener {
 	protected ResourceChangeListenerList listeners;
 	protected Workspace workspace;
 	protected ElementTree oldState;
@@ -80,19 +80,6 @@
 	}
 }
 
-public void changing(IProject project) {
-}
-
-public void closing(IProject project) {
-	if (!listeners.hasListenerFor(IResourceChangeEvent.PRE_CLOSE))
-		return;
-	notify(getListeners(), new ResourceChangeEvent(workspace, IResourceChangeEvent.PRE_CLOSE, project), true);
-}
-public void deleting(IProject project) {
-	if (!listeners.hasListenerFor(IResourceChangeEvent.PRE_DELETE))
-		return;
-	notify(getListeners(), new ResourceChangeEvent(workspace, IResourceChangeEvent.PRE_DELETE, project), true);
-}
 protected ResourceDelta getDelta(ElementTree tree) {
 	long id = workspace.getMarkerManager().getChangeId();
 	// if we have a delta from last time and no resources have changed since then, we
@@ -117,6 +104,23 @@
 	}
 	return result;
 }
+public void handleEvent(LifecycleEvent event) {
+	switch (event.kind) {
+		case LifecycleEvent.PRE_PROJECT_CLOSE:
+			if (!listeners.hasListenerFor(IResourceChangeEvent.PRE_CLOSE))
+				return;
+			IProject project = (IProject)event.resource;
+			notify(getListeners(), new ResourceChangeEvent(workspace, IResourceChangeEvent.PRE_CLOSE, project), true);
+			break;
+
+		case LifecycleEvent.PRE_PROJECT_DELETE:
+			if (!listeners.hasListenerFor(IResourceChangeEvent.PRE_DELETE))
+				return;
+			project = (IProject)event.resource;
+			notify(getListeners(), new ResourceChangeEvent(workspace, IResourceChangeEvent.PRE_DELETE, project), true);
+			break;
+	}
+}
 private void notify(ResourceChangeListenerList.ListenerEntry[] resourceListeners, final IResourceChangeEvent event, boolean lockTree) {
 	int type = event.getType();
 	for (int i = 0; i < resourceListeners.length; i++) {
@@ -154,8 +158,6 @@
 		}
 	}
 }
-public void opening(IProject project) {
-}
 public void removeListener(IResourceChangeListener listener) {
 	synchronized (listeners) {
 		listeners.remove(listener);
@@ -169,5 +171,8 @@
 	// tell the workspace to track changes from there.  This gives the
 	// notificaiton manager an initial basis for comparison.
 	oldState = workspace.getElementTree();
+	workspace.addLifecycleListener(this);
 }
+
+
 }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java
index f10fe29..5c3abae 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java
@@ -13,6 +13,8 @@
 import java.util.Enumeration;
 import java.util.List;
 
+import org.eclipse.core.internal.events.ILifecycleListener;
+import org.eclipse.core.internal.events.LifecycleEvent;
 import org.eclipse.core.internal.resources.*;
 import org.eclipse.core.internal.utils.Assert;
 import org.eclipse.core.internal.utils.Policy;
@@ -21,13 +23,11 @@
 /**
  *
  */
-public class PropertyManager implements IManager {
+public class PropertyManager implements IManager, ILifecycleListener {
 	protected Workspace workspace;
 public PropertyManager(Workspace workspace) {
 	this.workspace = workspace;
 }
-public void changing(IProject target) {
-}
 public void closePropertyStore(IResource target) throws CoreException {
 	Resource host = (Resource) getPropertyHost(target);
 	ResourceInfo info = (ResourceInfo) host.getResourceInfo(false, false);
@@ -41,9 +41,6 @@
 		setPropertyStore(target, null);
 	}
 }
-public void closing(IProject target) throws CoreException {
-	closePropertyStore(target);
-}
 /**
  * Copy all the properties of one resource to another. Both resources
  * must have a property store available.
@@ -101,8 +98,6 @@
 	closePropertyStore(target);
 	workspace.getMetaArea().getPropertyStoreLocation(target).toFile().delete();
 }
-public void deleting(IProject project) {
-}
 /**
  * Returns the value of the identified property on the given resource as
  * maintained by this store.
@@ -152,7 +147,9 @@
 		throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, e);
 	}
 }
-public void opening(IProject target) throws CoreException {
+public void handleEvent(LifecycleEvent event) throws CoreException {
+	if (event.kind == LifecycleEvent.PRE_PROJECT_CLOSE) 
+		closePropertyStore(event.resource);
 }
 protected PropertyStore openPropertyStore(IResource target) {
 	int type = target.getType();
@@ -190,5 +187,8 @@
 	closePropertyStore(workspace.getRoot());
 }
 public void startup(IProgressMonitor monitor) throws CoreException {
+	workspace.addLifecycleListener(this);
 }
+
+
 }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/AliasManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/AliasManager.java
index 3d543a0..8bf2a92 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/AliasManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/AliasManager.java
@@ -12,7 +12,8 @@
 
 import java.util.*;
 
-import org.eclipse.core.internal.utils.Assert;
+import org.eclipse.core.internal.events.ILifecycleListener;
+import org.eclipse.core.internal.events.LifecycleEvent;
 import org.eclipse.core.internal.utils.Policy;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
@@ -38,10 +39,10 @@
  * that it's better to incur this cost on startup than on the first attempt to
  * modify a resource.  After startup, the state is updated incrementally on the
  * following occasions: 
- *  - when projects are created, deleted, opened, closed, or moved 
+ *  -  when projects are deleted, opened, closed, or moved 
  *  - when linked resources are created, deleted, or moved.
  */
-public class AliasManager implements IManager {
+public class AliasManager implements IManager, ILifecycleListener {
 	/**
 	 * Maintains a mapping of IPath->IResource, such that multiple resources
 	 * mapped from the same path are tolerated.
@@ -176,23 +177,22 @@
 		IPath location = project.getLocation();
 		if (location != null)
 			locationsMap.add(location, project);
-		IResource[] members = null;
 		try {
-			members = project.members();
+			IResource[] members = project.members();
+			if (members != null)
+				//look for linked resources
+				for (int i = 0; i < members.length; i++)
+					if (members[i].isLinked())
+						addToLocationsMap(members[i]);
 		} catch (CoreException e) {
 			//skip inaccessible projects
 		}
-		if (members != null) {
-			//look for linked resources
-			for (int j = 0; j < members.length; j++) {
-				if (members[j].isLinked()) {
-					location = members[j].getLocation();
-					if (location != null)
-						if (locationsMap.add(location, members[j]))
-							linkedResourceCount++;
-				}
-			}
-		}
+	}
+	private void addToLocationsMap(IResource linkedResource) {
+		IPath location = linkedResource.getLocation();
+		if (location != null)
+			if (locationsMap.add(location, linkedResource))
+				linkedResourceCount++;
 	}
 
 	/**
@@ -203,7 +203,7 @@
 		//if there are no linked resources then there can't be any aliased projects
 		if (linkedResourceCount <= 0) {
 			//paranoid check -- count should never be below zero
-			Assert.isTrue(linkedResourceCount == 0, "Linked resource count below zero");//$NON-NLS-1$
+//			Assert.isTrue(linkedResourceCount == 0, "Linked resource count below zero");//$NON-NLS-1$
 			return;
 		}
 		//for every resource that overlaps another, marked its project as aliased
@@ -226,13 +226,7 @@
 			addToLocationsMap(projects[i]);
 		}
 	}
-	public void changing(IProject project) {
-	}
-	public void closing(IProject project) {
-		//same as deleting for purposes of alias data
-		deleting(project);
-	}
-	public void deleting(IProject project) {
+	public void removeFromLocationsMap(IProject project) {
 		//remove this project and all linked children from the location table
 		IPath location = project.getLocation();
 		if (location != null)
@@ -246,14 +240,12 @@
 		if (children != null) {
 			for (int i = 0; i < children.length; i++) {
 				if (children[i].isLinked()) {
-					deleting(children[i]);
+					removeFromLocationsMap(children[i]);
 				}
 			}
 		}
-		//rebuild the set of aliased projects from scratch
-		buildAliasedProjectsSet();
 	}
-	public void deleting(IResource linkedResource) {
+	public void removeFromLocationsMap(IResource linkedResource) {
 		//this linked resource is being deleted
 		IPath location = linkedResource.getLocation();
 		if (location != null)
@@ -286,10 +278,33 @@
 			}
 		};
 	}
-	public void opening(IProject project) {
-		addToLocationsMap(project);
+	public void handleEvent(LifecycleEvent event) throws CoreException {
+		switch (event.kind) {
+			case LifecycleEvent.PRE_PROJECT_CLOSE:
+			case LifecycleEvent.PRE_PROJECT_DELETE:
+				removeFromLocationsMap((IProject)event.resource);
+				break;
+			case LifecycleEvent.PRE_PROJECT_MOVE:
+			case LifecycleEvent.PRE_PROJECT_OPEN:
+				addToLocationsMap((IProject)event.resource);
+				buildAliasedProjectsSet();
+				break;
+			case LifecycleEvent.PRE_LINK_DELETE:
+			case LifecycleEvent.PRE_LINK_MOVE:
+			case LifecycleEvent.POST_LINK_CREATE:
+		}
+		//rebuild the set of aliased projects from scratch
 		buildAliasedProjectsSet();
 	}
+	/**
+	 * Method moving.
+	 * @param source
+	 * @param destination
+	 * @param updateFlags
+	 */
+	public void moving(IResource source, IResource destination, int updateFlags) {
+		// todo
+	}
 
 	/**
 	 * @see IManager#shutdown
@@ -301,9 +316,11 @@
 	 * @see IManager#startup
 	 */
 	public void startup(IProgressMonitor monitor) throws CoreException {
+		workspace.addLifecycleListener(this);
 		buildLocationsMap();
 		buildAliasedProjectsSet();
 	}
+
 	/**
 	 * The file underlying the given resource has changed on disk.  Compute all
 	 * aliases for this resource and update them.  This method will not attempt
@@ -330,4 +347,11 @@
 		// todo
 		return null;
 	}
+	/**
+	 * Notification of creation of a linked reousr.cds
+	 */
+	public void creating(IResource linkedResource) {
+		addToLocationsMap(linkedResource);
+		buildAliasedProjectsSet();
+	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
index 5e73fd6..2761163 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Container.java
@@ -69,11 +69,9 @@
 /**
  */
 protected void fixupAfterMoveSource() throws CoreException {
-	if (!synchronizing(getResourceInfo(false, false)) || getType() == PROJECT) {
-		workspace.deleteResource(this);
-		return;
-	}
 	super.fixupAfterMoveSource();
+	if (!synchronizing(getResourceInfo(false, false)))
+		return;
 	IResource[] members = members(IContainer.INCLUDE_PHANTOMS | IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
 	for (int i = 0; i < members.length; i++)
 		 ((Resource) members[i]).fixupAfterMoveSource();
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerManager.java
index 65163b6..a64a78f 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerManager.java
@@ -197,22 +197,6 @@
 		info.incrementMarkerGenerationCount();
 }
 /**
- * Internal workspace lifecycle event
- */
-public void changing(IProject project) {
-}
-/**
- * Internal workspace lifecycle event
- */
-public void closing(IProject project) {
-}
-/**
- * Internal workspace lifecycle event
- */
-public void deleting(IProject project) {
-}
-
-/**
  * Returns the marker with the given id or <code>null</code> if none is found.
  */
 public IMarker findMarker(IResource resource, long id) {
@@ -332,11 +316,6 @@
 	destination.accept(visitor, depth, false);
 }
 /**
- * Internal workspace lifecycle event
- */
-public void opening(IProject project) {
-}
-/**
  * Adds the markers for a subtree of resources to the list.
  */
 private void recursiveFindMarkers(IPath path, ArrayList list, String type, boolean includeSubtypes, int depth) {
@@ -483,4 +462,6 @@
  */
 public void startup(IProgressMonitor monitor) throws CoreException {
 }
+
+
 }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/NatureManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/NatureManager.java
index 32e23b6..69b11b4 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/NatureManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/NatureManager.java
Binary files differ
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
index 2c54395..9d5a29f 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
Binary files differ
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Resource.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Resource.java
index 08a522e..0313600 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Resource.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Resource.java
@@ -475,7 +475,8 @@
 				new LinkDescription(this,localLocation));
 			project.writeDescription(IResource.NONE);
 			monitor.worked(Policy.opWork * 5 / 100);
-			
+			//notify internal infrastructure that link has been created
+			workspace.creating(this);
 			//refresh to discover any new resources below this linked location
 			if (getType() != IResource.FILE)
 				refreshLocal(DEPTH_INFINITE, Policy.subMonitorFor(monitor, Policy.opWork * 90 / 100));
@@ -625,6 +626,8 @@
 		getMarkerManager().removeMarkers(this, IResource.DEPTH_INFINITE);
 	// if this is a linked resource, remove the entry from the project description
 	if (isLinked()) {
+		//pre-delete notification to internal infrastructure
+		workspace.deleting(this);
 		Project project = (Project)getProject();
 		ProjectDescription description = project.internalGetDescription();
 		description.setLinkLocation(getName(), null);
@@ -681,6 +684,13 @@
 }
 protected void fixupAfterMoveSource() throws CoreException {
 	ResourceInfo info = getResourceInfo(true, true);
+	//if a linked resource is moved, we need to remove the location info from the .project 
+	if (isLinked()) {
+		Project project = (Project)getProject();
+		project.internalGetDescription().setLinkLocation(getName(), null);
+		project.writeDescription(IResource.NONE);
+	}
+		
 	if (!synchronizing(info)) {
 		workspace.deleteResource(this);
 		return;
@@ -984,20 +994,19 @@
 }
 
 /**
- * @see IResource#move
- */
-public void move(IPath destination, boolean force, IProgressMonitor monitor) throws CoreException {
-	move(destination, force ? IResource.FORCE : IResource.NONE, monitor);
-}
-
-/**
- * @see IResource#move
+ * @see IFolder#move and IFile#move
  */
 public void move(IPath destination, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException {
 	int updateFlags = force ? IResource.FORCE : IResource.NONE;
 	updateFlags |= keepHistory ? IResource.KEEP_HISTORY : IResource.NONE;
 	move(destination, updateFlags, monitor);
 }
+/**
+ * @see IResource#move
+ */
+public void move(IPath destination, boolean force, IProgressMonitor monitor) throws CoreException {
+	move(destination, force ? IResource.FORCE : IResource.NONE, monitor);
+}
 
 /**
  * @see IResource#move
@@ -1031,14 +1040,13 @@
 					break;
 				case IResource.PROJECT:
 					IProject project = (IProject) this;
-					// if there is a change in name, then we are deleting the source project so notify.
-					// else there is nothing to do so return.
+					// if there is no change in name, there is nothing to do so return.
 					if (getName().equals(path.lastSegment())) {
 						return;
-					} else {
-						workspace.changing(project);
-						workspace.deleting(project);
 					}
+					//we are deleting the source project so notify.
+					workspace.changing(project);
+					workspace.deleting(project);
 					IProjectDescription description = project.getDescription();
 					description.setName(path.lastSegment());
 					if (!hook.moveProject(tree, project, description, updateFlags, Policy.subMonitorFor(monitor, Policy.opWork/2)))
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
index d12b7bb..d093a1f 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
@@ -26,6 +26,7 @@
 
 
 public class Workspace extends PlatformObject implements IWorkspace, ICoreConstants {
+
 	protected WorkspaceDescription description;
 	protected LocalMetaArea localMetaArea;
 	protected boolean openFlag = false;
@@ -39,13 +40,16 @@
 	protected PathVariableManager pathVariableManager;
 	protected PropertyManager propertyManager;
 	protected MarkerManager markerManager;
+	protected WorkManager workManager;
+	protected AliasManager aliasManager;
 	protected long nextNodeId = 0;
 	protected long nextModificationStamp = 0;
 	protected long nextMarkerId = 0;
 	protected Synchronizer synchronizer;
-	protected WorkManager workManager;
 	protected IProject[] buildOrder = null;
 	protected IWorkspaceRoot defaultRoot = new WorkspaceRoot(Path.ROOT, this);
+	
+	protected final ArrayList lifecycleListeners = new ArrayList(10);
 
 	protected static final String REFRESH_ON_STARTUP = "-refresh"; //$NON-NLS-1$
 	
@@ -95,6 +99,13 @@
 	tree.setTreeData(newElement(IResource.ROOT));
 }
 /**
+ * Adds a listener for internal workspace lifecycle events.  There is no way to
+ * remove lifecycle listeners.
+ */
+public void addLifecycleListener(ILifecycleListener listener) {
+	lifecycleListeners.add(listener);
+}
+/**
  * @see IWorkspace
  */
 public void addResourceChangeListener(IResourceChangeListener listener) {
@@ -140,6 +151,14 @@
 	monitor.subTask(Policy.bind("resources.updating")); //$NON-NLS-1$
 	notificationManager.broadcastChanges(currentTree, type, lockTree, updateState);
 }
+/**
+ * Broadcasts an internal workspace lifecycle event to interested
+ * internal listeners.
+ */
+protected void broadcastEvent(LifecycleEvent event) throws CoreException {
+	
+}
+
 public void build(int trigger, IProgressMonitor monitor) throws CoreException {
 	monitor = Policy.monitorFor(monitor);
 	try {
@@ -168,6 +187,7 @@
 	notificationManager.changing(project);
 	propertyManager.changing(project);
 	markerManager.changing(project);
+	aliasManager.changing(project);
 }
 /**
  * @see IWorkspace#checkpoint
@@ -281,6 +301,7 @@
 	notificationManager.closing(project);
 	propertyManager.closing(project);
 	markerManager.closing(project);
+	aliasManager.closing(project);
 }
 
 /**
@@ -690,6 +711,15 @@
 	}
 	return info;
 }
+/**
+ * Notify relevant infrastructure pieces that a linked resource is being
+ * created.
+ */
+public void creating(IResource linkedResource) {
+	aliasManager.creating(linkedResource);
+}
+
+
 /*
  * Creates the given resource in the tree and returns the new resource info object.  
  * If phantom is true, the created element is marked as a phantom.
@@ -814,8 +844,18 @@
 	notificationManager.deleting(project);
 	propertyManager.deleting(project);
 	markerManager.deleting(project);
+	aliasManager.deleting(project);
 }
 /**
+ * Notify relevant infrastructure pieces that a linked resources is being
+ * deleted.  This is needed because the linked resource location is no longer
+ * available after the operation is completed.
+ */
+protected void deleting(IResource linkedResource) throws CoreException {
+	aliasManager.deleting(linkedResource);
+}
+	
+/**
  * For debugging purposes only.  Dumps plugin stats to console
  */
 public void dumpStats() {
@@ -1388,6 +1428,23 @@
 	source.fixupAfterMoveSource();
 }
 /**
+ * Notify the relevant infrastructure pieces that the given project or linked
+ * resource is being moved.
+ */
+protected void moving(IResource source, IResource destination, int updateFlags) {
+	//most infrastructure only cares about project deletion
+	if (source.getType() == IResource.PROJECT) {
+		IProject project = (IProject)source;
+		buildManager.deleting(project);
+		natureManager.deleting(project);
+		notificationManager.deleting(project);
+		propertyManager.deleting(project);
+		markerManager.deleting(project);
+	}
+	aliasManager.moving(source, destination, updateFlags);
+}
+
+/**
  * Create and return a new tree element of the given type.
  */
 protected ResourceInfo newElement(int type) {
@@ -1533,6 +1590,7 @@
 	notificationManager.opening(project);
 	propertyManager.opening(project);
 	markerManager.opening(project);
+	aliasManager.opening(project);
 }
 /**
  * Called before checking the pre-conditions of an operation.
@@ -1696,6 +1754,7 @@
 	pathVariableManager = new PathVariableManager(this);
 	pathVariableManager.startup(null);
 	natureManager = new NatureManager();
+	natureManager.startup(null);
 	buildManager = new BuildManager(this);
 	buildManager.startup(null);
 	notificationManager = new NotificationManager(this);
@@ -1705,6 +1764,10 @@
 	synchronizer = new Synchronizer(this);
 	saveManager = new SaveManager(this);
 	saveManager.startup(null);
+	//must start after save manager, because (read) access to tree is needed
+	aliasManager = new AliasManager(this);
+	aliasManager.startup(null);
+	
 	treeLocked = false; // unlock the tree.
 }
 /** 
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
index f888a9e..907e2a7 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
@@ -83,6 +83,7 @@
 links.moveNotProject = Cannot move {0} to {1}.  Linked resources must have a project as their parent.
 links.natureVeto = Linking is not allowed because project nature \"{0}\" does not allow it.
 links.overlappingResource = Location {0} may overlap the location of another resource in the same workspace. This is permitted, but may have unexpected side-effects because changing one resource may now cause several resources to change.
+links.updatingDuplicate = Updating duplicate resource: {0}.
 links.parentNotProject = Cannot create linked resource {0}.  Linked resources must have a project as their parent.
 links.vetoNature = Cannot add nature because project {0} contains linked resources, and nature \"{1}\" does not allow it.
 links.wrongLocalType = Cannot create linked resource {0}.  Files cannot be linked to folders.