Bug 295007 [services] selection service implementation discussion
diff --git a/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF
index de67a45..f6a9d0f 100644
--- a/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF
@@ -26,5 +26,5 @@
  org.eclipse.e4.workbench.ui.behaviors,
  org.eclipse.e4.workbench.ui.internal;x-friends:="org.eclipse.e4.ui.workbench.fragment,org.eclipse.e4.ui.workbench.renderers.swt"
 Bundle-Activator: org.eclipse.e4.workbench.ui.internal.Activator
-Service-Component: OSGI-INF/progress.xml, OSGI-INF/partService.xml, OSGI-INF/modelService.xml
+Service-Component: OSGI-INF/progress.xml, OSGI-INF/partService.xml, OSGI-INF/modelService.xml, OSGI-INF/selectionLookup.xml, OSGI-INF/selectionService.xml
 Import-Package: javax.inject;version="1.0.0"
diff --git a/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionLookup.xml b/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionLookup.xml
new file mode 100644
index 0000000..14e6d3b
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionLookup.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.ui.selection.lookUp">
+   <implementation class="org.eclipse.e4.workbench.ui.internal.SelectionLookupFunction"/>
+   <service>
+      <provide interface="org.eclipse.e4.core.services.context.IContextFunction"/>
+   </service>
+   <property name="service.context.key" type="String" value="in.selection"/>
+</scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionService.xml b/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionService.xml
new file mode 100644
index 0000000..5b480d8
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/OSGI-INF/selectionService.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.ui.selection.ESelectionService">
+   <implementation class="org.eclipse.e4.workbench.ui.internal.SelectionServiceCreationFunction"/>
+   <service>
+      <provide interface="org.eclipse.e4.core.services.context.IContextFunction"/>
+   </service>
+   <property name="service.context.key" type="String" value="org.eclipse.e4.workbench.modeling.ESelectionService"/>
+</scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ESelectionService.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ESelectionService.java
new file mode 100644
index 0000000..c80586e
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ESelectionService.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.workbench.modeling;
+
+/**
+ * @since 1.0
+ */
+public interface ESelectionService {
+
+	public static final String SELECTION = "in.selection"; //$NON-NLS-1$
+
+	public void setSelection(Object selection);
+
+	public Object getSelection();
+
+	public Object getSelection(String partId);
+
+	public void addSelectionListener(ISelectionListener listener);
+
+	public void removeSelectionListener(ISelectionListener listener);
+
+	public void addSelectionListener(String partId, ISelectionListener listener);
+
+	public void removeSelectionListener(String partId, ISelectionListener listener);
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ISelectionListener.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ISelectionListener.java
new file mode 100644
index 0000000..8afbe54
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/modeling/ISelectionListener.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.workbench.modeling;
+
+import org.eclipse.e4.ui.model.application.MPart;
+
+/**
+ * @since 1.0
+ */
+public interface ISelectionListener {
+
+	public void selectionChanged(MPart part, Object selection);
+
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionLookupFunction.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionLookupFunction.java
new file mode 100644
index 0000000..b6b8994
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionLookupFunction.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.workbench.ui.internal;
+
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.core.services.context.spi.ContextFunction;
+import org.eclipse.e4.core.services.context.spi.IContextConstants;
+
+/**
+ *
+ */
+public class SelectionLookupFunction extends ContextFunction {
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.e4.core.services.context.spi.ContextFunction#compute(org.eclipse.e4.core.services
+	 * .context.IEclipseContext, java.lang.Object[])
+	 */
+	@Override
+	public Object compute(IEclipseContext context, Object[] arguments) {
+		IEclipseContext leafContext = context;
+		IEclipseContext child = (IEclipseContext) leafContext
+				.getLocal(IContextConstants.ACTIVE_CHILD);
+		while (child != null) {
+			leafContext = child;
+			child = (IEclipseContext) leafContext.getLocal(IContextConstants.ACTIVE_CHILD);
+		}
+		return leafContext.get(SelectionServiceImpl.OUT_SELECTION);
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceCreationFunction.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceCreationFunction.java
new file mode 100644
index 0000000..3d03464
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceCreationFunction.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.workbench.ui.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.e4.core.services.Logger;
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.core.services.context.spi.ContextFunction;
+import org.eclipse.e4.core.services.context.spi.ContextInjectionFactory;
+
+/**
+ *
+ */
+public class SelectionServiceCreationFunction extends ContextFunction {
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.e4.core.services.context.spi.ContextFunction#compute(org.eclipse.e4.core.services
+	 * .context.IEclipseContext, java.lang.Object[])
+	 */
+	@Override
+	public Object compute(IEclipseContext context, Object[] arguments) {
+		try {
+			return ContextInjectionFactory.make(SelectionServiceImpl.class, context);
+		} catch (InvocationTargetException e) {
+			Logger logger = (Logger) context.get(Logger.class.getName());
+			if (logger != null) {
+				logger.error(e);
+			}
+		} catch (InstantiationException e) {
+			Logger logger = (Logger) context.get(Logger.class.getName());
+			if (logger != null) {
+				logger.error(e);
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceImpl.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceImpl.java
new file mode 100644
index 0000000..77bab1c
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/workbench/ui/internal/SelectionServiceImpl.java
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.workbench.ui.internal;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.eclipse.e4.core.services.annotations.Optional;
+import org.eclipse.e4.core.services.annotations.PostConstruct;
+import org.eclipse.e4.core.services.annotations.PreDestroy;
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MElementContainer;
+import org.eclipse.e4.ui.model.application.MPart;
+import org.eclipse.e4.ui.model.application.MWindow;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.services.events.IEventBroker;
+import org.eclipse.e4.workbench.modeling.EPartService;
+import org.eclipse.e4.workbench.modeling.ESelectionService;
+import org.eclipse.e4.workbench.modeling.ISelectionListener;
+import org.eclipse.e4.workbench.ui.UIEvents;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+public class SelectionServiceImpl implements ESelectionService {
+
+	static final String OUT_SELECTION = "output.selection"; //$NON-NLS-1$
+
+	private Set<ISelectionListener> genericListeners = new HashSet<ISelectionListener>();
+	private Map<String, Set<ISelectionListener>> targetedListeners = new HashMap<String, Set<ISelectionListener>>();
+	private Set<IEclipseContext> tracked = new HashSet<IEclipseContext>();
+
+	@Inject
+	private IEclipseContext context;
+
+	@Inject
+	private EPartService partService;
+
+	/**
+	 * This is the specific implementation. TODO: generalize it
+	 */
+	@Inject
+	@Named(EPartService.PART_SERVICE_ROOT)
+	private MWindow serviceRoot;
+
+	@Inject
+	private IEventBroker eventBroker;
+
+	private EventHandler eventHandler = new EventHandler() {
+		public void handleEvent(Event event) {
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			if (element instanceof MPart) {
+				MPart part = (MPart) element;
+				IEclipseContext context = part.getContext();
+				if (context != null && isInContainer(part)) {
+					track(part);
+				}
+			}
+		}
+	};
+
+	private MPart activePart;
+
+	@PreDestroy
+	void preDestroy() {
+		IEclipseContext rootContext = serviceRoot.getContext();
+		if (rootContext != context) {
+			ESelectionService selectionService = (ESelectionService) rootContext
+					.get(ESelectionService.class.getName());
+			for (ISelectionListener listener : genericListeners) {
+				selectionService.removeSelectionListener(listener);
+			}
+
+			for (Entry<String, Set<ISelectionListener>> entry : targetedListeners.entrySet()) {
+				String partId = entry.getKey();
+				for (ISelectionListener listener : entry.getValue()) {
+					selectionService.removeSelectionListener(partId, listener);
+				}
+			}
+		}
+
+		genericListeners.clear();
+		targetedListeners.clear();
+
+		eventBroker.unsubscribe(eventHandler);
+	}
+
+	@PostConstruct
+	void postConstruct() {
+		eventBroker
+				.subscribe(UIEvents.buildTopic(UIEvents.Context.TOPIC, UIEvents.Context.CONTEXT),
+						eventHandler);
+
+		for (MPart part : partService.getParts()) {
+			track(part);
+		}
+	}
+
+	@Inject
+	void setPart(@Optional @Named(IServiceConstants.ACTIVE_PART) final MPart part) {
+		if (part != null) {
+			activePart = part;
+			IEclipseContext rootContext = serviceRoot.getContext();
+			if (rootContext == context) {
+				final IEclipseContext partContext = part.getContext();
+				Object selection = partContext.get(OUT_SELECTION);
+				notifyListeners(part, selection);
+
+				track(part);
+			}
+		}
+	}
+
+	private boolean isInContainer(MPart part) {
+		return isInContainer(serviceRoot, part);
+	}
+
+	private boolean isInContainer(MElementContainer<?> container, MPart part) {
+		for (Object object : container.getChildren()) {
+			if (object == part) {
+				return true;
+			} else if (object instanceof MElementContainer<?>) {
+				if (isInContainer((MElementContainer<?>) object, part)) {
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	private void notifyListeners(MPart part, Object selection) {
+		for (ISelectionListener listener : genericListeners) {
+			listener.selectionChanged(part, selection);
+		}
+
+		notifyTargetedListeners(part, selection);
+	}
+
+	private void notifyTargetedListeners(MPart part, Object selection) {
+		String id = part.getId();
+		if (id != null) {
+			Set<ISelectionListener> listeners = targetedListeners.get(id);
+			if (listeners != null) {
+				for (ISelectionListener listener : listeners) {
+					listener.selectionChanged(part, selection);
+				}
+			}
+		}
+	}
+
+	private void track(final MPart part) {
+		final IEclipseContext context = part.getContext();
+		if (context != null && tracked.add(context)) {
+			context.runAndTrack(new Runnable() {
+
+				private boolean initial = true;
+
+				public void run() {
+					Object selection = context.get(OUT_SELECTION);
+					if (initial) {
+						initial = false;
+						if (selection == null) {
+							return;
+						}
+					}
+
+					if (activePart == part) {
+						notifyListeners(part, selection);
+					} else {
+						notifyTargetedListeners(part, selection);
+					}
+				}
+			});
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.e4.ui.selection.ESelectionService#setSelection(java.lang.Object)
+	 */
+	public void setSelection(Object selection) {
+		if (selection != null) {
+			context.set(OUT_SELECTION, selection);
+		} else {
+			context.remove(OUT_SELECTION);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.e4.ui.selection.ESelectionService#getSelection()
+	 */
+	public Object getSelection() {
+		return activePart.getContext().get(ESelectionService.SELECTION);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.e4.ui.selection.ESelectionService#addSelectionListener(org.eclipse.e4.ui.selection
+	 * .ISelectionListener)
+	 */
+	public void addSelectionListener(ISelectionListener listener) {
+		IEclipseContext rootContext = serviceRoot.getContext();
+		if (rootContext != context) {
+			ESelectionService selectionService = (ESelectionService) rootContext
+					.get(ESelectionService.class.getName());
+			selectionService.addSelectionListener(listener);
+		}
+
+		genericListeners.add(listener);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.e4.ui.selection.ESelectionService#removeSelectionListener(org.eclipse.e4.ui.selection
+	 * .ISelectionListener)
+	 */
+	public void removeSelectionListener(ISelectionListener listener) {
+		IEclipseContext rootContext = serviceRoot.getContext();
+		if (rootContext != context) {
+			ESelectionService selectionService = (ESelectionService) rootContext
+					.get(ESelectionService.class.getName());
+			selectionService.removeSelectionListener(listener);
+		}
+
+		genericListeners.remove(listener);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.e4.ui.selection.ESelectionService#addSelectionListener(java.lang.String,
+	 * org.eclipse.e4.ui.selection.ISelectionListener)
+	 */
+	public void addSelectionListener(String partId, ISelectionListener listener) {
+		IEclipseContext rootContext = serviceRoot.getContext();
+		if (rootContext != context) {
+			ESelectionService selectionService = (ESelectionService) rootContext
+					.get(ESelectionService.class.getName());
+			selectionService.addSelectionListener(partId, listener);
+		}
+
+		Set<ISelectionListener> listeners = targetedListeners.get(partId);
+		if (listeners == null) {
+			listeners = new HashSet<ISelectionListener>();
+			targetedListeners.put(partId, listeners);
+		}
+		listeners.add(listener);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.e4.ui.selection.ESelectionService#removeSelectionListener(java.lang.String,
+	 * org.eclipse.e4.ui.selection.ISelectionListener)
+	 */
+	public void removeSelectionListener(String partId, ISelectionListener listener) {
+		IEclipseContext rootContext = serviceRoot.getContext();
+		if (rootContext != context) {
+			ESelectionService selectionService = (ESelectionService) rootContext
+					.get(ESelectionService.class.getName());
+			selectionService.removeSelectionListener(partId, listener);
+		}
+
+		Set<ISelectionListener> listeners = targetedListeners.get(partId);
+		if (listeners != null) {
+			listeners.remove(listener);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.e4.ui.selection.ESelectionService#getSelection(java.lang.String)
+	 */
+	public Object getSelection(String partId) {
+		MPart part = partService.findPart(partId);
+		if (part == null) {
+			return null;
+		}
+
+		IEclipseContext partContext = part.getContext();
+		if (partContext == null) {
+			return null;
+		}
+		return partContext.get(OUT_SELECTION);
+	}
+
+}
diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/ESelectionServiceTest.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/ESelectionServiceTest.java
new file mode 100644
index 0000000..7c144d2
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/ESelectionServiceTest.java
@@ -0,0 +1,924 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.ui.tests.application;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import junit.framework.TestCase;
+
+import org.eclipse.e4.core.services.IContributionFactory;
+import org.eclipse.e4.core.services.IDisposable;
+import org.eclipse.e4.core.services.annotations.Optional;
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.core.services.context.spi.ContextInjectionFactory;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.MApplicationFactory;
+import org.eclipse.e4.ui.model.application.MPart;
+import org.eclipse.e4.ui.model.application.MPartStack;
+import org.eclipse.e4.ui.model.application.MWindow;
+import org.eclipse.e4.ui.workbench.swt.internal.E4Application;
+import org.eclipse.e4.workbench.modeling.EPartService;
+import org.eclipse.e4.workbench.modeling.ESelectionService;
+import org.eclipse.e4.workbench.modeling.ISelectionListener;
+import org.eclipse.e4.workbench.modeling.EPartService.PartState;
+import org.eclipse.e4.workbench.ui.IPresentationEngine;
+import org.eclipse.e4.workbench.ui.internal.UIEventPublisher;
+import org.eclipse.e4.workbench.ui.internal.Workbench;
+import org.eclipse.emf.common.notify.Notifier;
+
+public class ESelectionServiceTest extends TestCase {
+
+	private IEclipseContext applicationContext;
+
+	private IPresentationEngine engine;
+
+	@Override
+	protected void setUp() throws Exception {
+		applicationContext = E4Application.createDefaultContext();
+
+		super.setUp();
+	}
+
+	protected String getEngineURI() {
+		return "platform:/plugin/org.eclipse.e4.ui.tests/org.eclipse.e4.ui.tests.application.HeadlessContextPresentationEngine"; //$NON-NLS-1$
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		if (applicationContext instanceof IDisposable) {
+			((IDisposable) applicationContext).dispose();
+		}
+	}
+
+	private IPresentationEngine getEngine() {
+		if (engine == null) {
+			IContributionFactory contributionFactory = (IContributionFactory) applicationContext
+					.get(IContributionFactory.class.getName());
+			Object newEngine = contributionFactory.create(getEngineURI(),
+					applicationContext);
+			assertTrue(newEngine instanceof IPresentationEngine);
+			applicationContext.set(IPresentationEngine.class.getName(),
+					newEngine);
+
+			engine = (IPresentationEngine) newEngine;
+		}
+
+		return engine;
+	}
+
+	public void testGetSelection() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextA = partA.getContext();
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceA = (ESelectionService) contextA
+				.get(ESelectionService.class.getName());
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selection1 = new Object();
+		Object selection2 = new Object();
+
+		serviceA.setSelection(selection1);
+
+		assertEquals(selection1, windowService.getSelection());
+		assertEquals(selection1, serviceA.getSelection());
+		assertEquals(selection1, serviceB.getSelection());
+
+		serviceB.setSelection(selection2);
+
+		assertEquals(selection1, windowService.getSelection());
+		assertEquals(selection1, serviceA.getSelection());
+		assertEquals(selection1, serviceB.getSelection());
+
+		partService.activate(partB);
+
+		assertEquals(selection2, windowService.getSelection());
+		assertEquals(selection2, serviceA.getSelection());
+		assertEquals(selection2, serviceB.getSelection());
+	}
+
+	public void testGetSelection_Id() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextA = partA.getContext();
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceA = (ESelectionService) contextA
+				.get(ESelectionService.class.getName());
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+
+		Object selection1 = new Object();
+		Object selection2 = new Object();
+
+		serviceA.setSelection(selection1);
+
+		assertEquals(selection1, windowService.getSelection("partA")); //$NON-NLS-1$
+		assertEquals(selection1, serviceA.getSelection("partA")); //$NON-NLS-1$
+		assertEquals(selection1, serviceB.getSelection("partA")); //$NON-NLS-1$
+		assertNull(windowService.getSelection("partB")); //$NON-NLS-1$
+		assertNull(serviceA.getSelection("partB")); //$NON-NLS-1$
+		assertNull(serviceB.getSelection("partB")); //$NON-NLS-1$
+
+		serviceB.setSelection(selection2);
+
+		assertEquals(selection1, windowService.getSelection("partA")); //$NON-NLS-1$
+		assertEquals(selection1, serviceA.getSelection("partA")); //$NON-NLS-1$
+		assertEquals(selection1, serviceB.getSelection("partA")); //$NON-NLS-1$
+		assertEquals(selection2, windowService.getSelection("partB")); //$NON-NLS-1$
+		assertEquals(selection2, serviceA.getSelection("partB")); //$NON-NLS-1$
+		assertEquals(selection2, serviceB.getSelection("partB")); //$NON-NLS-1$
+	}
+
+	public void testSelectionListener() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selection = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener(listener);
+
+		serviceB.setSelection(selection);
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertEquals(partB, listener.getPart());
+		assertEquals(selection, listener.getSelection());
+
+		windowService.removeSelectionListener(listener);
+
+		listener.reset();
+		partService.activate(partA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+	}
+
+	public void testSelectionListener2() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextA = partA.getContext();
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceA = (ESelectionService) contextA
+				.get(ESelectionService.class.getName());
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selectionA = new Object();
+		Object selectionB = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener(listener);
+
+		serviceA.setSelection(selectionA);
+
+		assertEquals(partA, listener.getPart());
+		assertEquals(selectionA, listener.getSelection());
+
+		listener.reset();
+		serviceA.setSelection(selectionA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		serviceB.setSelection(selectionB);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertEquals(partB, listener.getPart());
+		assertEquals(selectionB, listener.getSelection());
+
+		windowService.removeSelectionListener(listener);
+
+		listener.reset();
+		partService.activate(partA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+	}
+
+	public void testSelectionListener3() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextA = partA.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceA = (ESelectionService) contextA
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selectionA = new Object();
+		Object selectionB = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener(listener);
+
+		serviceA.setSelection(selectionA);
+
+		assertEquals(partA, listener.getPart());
+		assertEquals(selectionA, listener.getSelection());
+
+		listener.reset();
+		serviceA.setSelection(selectionA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertEquals(partB, listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		serviceA.setSelection(selectionB);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+	}
+
+	public void testSelectionListener_Id() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextA = partA.getContext();
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceA = (ESelectionService) contextA
+				.get(ESelectionService.class.getName());
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selectionA = new Object();
+		Object selectionB = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener("partB", listener); //$NON-NLS-1$
+
+		serviceA.setSelection(selectionA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		partService.activate(partB);
+
+		assertEquals(partB, listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		serviceB.setSelection(selectionB);
+
+		assertEquals(partB, listener.getPart());
+		assertEquals(selectionB, listener.getSelection());
+
+		listener.reset();
+		serviceA.setSelection(selectionB);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		windowService.removeSelectionListener("partB", listener); //$NON-NLS-1$
+		serviceB.setSelection(selectionA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+	}
+
+	public void testSelectionListener_Id2() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		window.getChildren().add(partB);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext contextB = partB.getContext();
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService serviceB = (ESelectionService) contextB
+				.get(ESelectionService.class.getName());
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selectionB = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener("partB", listener); //$NON-NLS-1$
+
+		partService.activate(partA);
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		listener.reset();
+		serviceB.setSelection(selectionB);
+
+		assertEquals(partB, listener.getPart());
+		assertEquals(selectionB, listener.getSelection());
+	}
+
+	public void testSelectionListener_Id3() {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		partA.setId("partA"); //$NON-NLS-1$
+		window.getChildren().add(partA);
+		window.setSelectedElement(partA);
+
+		MPartStack partStack = MApplicationFactory.eINSTANCE.createPartStack();
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		partB.setId("partB"); //$NON-NLS-1$
+		partStack.getChildren().add(partB);
+		MPart partC = MApplicationFactory.eINSTANCE.createPart();
+		partC.setId("partC"); //$NON-NLS-1$
+		partStack.getChildren().add(partC);
+		partStack.setSelectedElement(partB);
+		window.getChildren().add(partStack);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext windowContext = window.getContext();
+
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selection = new Object();
+
+		SelectionListener listener = new SelectionListener();
+		windowService.addSelectionListener("partC", listener); //$NON-NLS-1$
+
+		partService.showPart("partC", PartState.CREATE); //$NON-NLS-1$
+
+		assertNull(listener.getPart());
+		assertNull(listener.getSelection());
+
+		IEclipseContext contextC = partC.getContext();
+		ESelectionService serviceC = (ESelectionService) contextC
+				.get(ESelectionService.class.getName());
+
+		listener.reset();
+		serviceC.setSelection(selection);
+
+		assertEquals(partC, listener.getPart());
+		assertEquals(selection, listener.getSelection());
+	}
+
+	static class ConsumerPart {
+		public Object input;
+
+		@Inject
+		@Optional
+		public void setInput(@Named(ESelectionService.SELECTION) Object current) {
+			input = current;
+		}
+	}
+
+	static class ProviderPart extends ConsumerPart {
+		private ESelectionService selectionService;
+
+		@Inject
+		public void setSelectionService(ESelectionService s) {
+			selectionService = s;
+		}
+
+		public void setSelection(Object selection) {
+			selectionService.setSelection(selection);
+		}
+	}
+
+	static class TrackingProviderPart extends ProviderPart {
+		public Object otherSelection;
+
+		public void setOtherSelection(Object selection) {
+			otherSelection = selection;
+		}
+	}
+
+	static class UseSelectionHandler {
+		public Object selection;
+
+		public void execute(
+				@Optional @Named(ESelectionService.SELECTION) Object s) {
+			selection = s;
+		}
+	}
+
+	public void testOnePartSelection() throws Exception {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		ProviderPart p = new ProviderPart();
+		ContextInjectionFactory.inject(p, window.getContext());
+
+		assertNull(p.input);
+
+		Object selection = new Object();
+
+		p.setSelection(selection);
+		assertEquals(selection, p.input);
+		p.setSelection(null);
+		assertNull(p.input);
+	}
+
+	public void testTwoPartHandlerExecute() throws Exception {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partA);
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partB);
+		window.setSelectedElement(partA);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext windowContext = window.getContext();
+
+		IEclipseContext partContextA = partA.getContext();
+		IEclipseContext partContextB = partB.getContext();
+
+		ProviderPart partOneImpl = new ProviderPart();
+		ContextInjectionFactory.inject(partOneImpl, partContextA);
+
+		ConsumerPart partTwoImpl = new ConsumerPart();
+		ContextInjectionFactory.inject(partTwoImpl, partContextB);
+
+		Object selection = new Object();
+
+		partOneImpl.setSelection(selection);
+
+		UseSelectionHandler handler = new UseSelectionHandler();
+		assertNull(handler.selection);
+
+		ContextInjectionFactory.invoke(handler, "execute", applicationContext,
+				null);
+		assertEquals(selection, handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", windowContext, null);
+		assertEquals(selection, handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", partContextA, null);
+		assertEquals(selection, handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", partContextB, null);
+		assertNull(handler.selection);
+
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+		partService.activate(partB);
+
+		ContextInjectionFactory.invoke(handler, "execute", applicationContext,
+				null);
+		assertNull(handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", windowContext, null);
+		assertNull(handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", partContextA, null);
+		assertEquals(selection, handler.selection);
+		handler.selection = null;
+
+		ContextInjectionFactory.invoke(handler, "execute", partContextB, null);
+		assertNull(handler.selection);
+	}
+
+	public void testThreePartSelection() throws Exception {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partA);
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partB);
+		MPart partC = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partC);
+		window.setSelectedElement(partA);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		IEclipseContext windowContext = window.getContext();
+		IEclipseContext partContextA = partA.getContext();
+		IEclipseContext partContextB = partB.getContext();
+		IEclipseContext partContextC = partC.getContext();
+
+		ProviderPart partOneImpl = new ProviderPart();
+		ContextInjectionFactory.inject(partOneImpl, partContextA);
+
+		ConsumerPart partTwoImpl = new ConsumerPart();
+		ContextInjectionFactory.inject(partTwoImpl, partContextB);
+
+		ProviderPart partThreeImpl = new ProviderPart();
+		ContextInjectionFactory.inject(partThreeImpl, partContextC);
+
+		ESelectionService windowService = (ESelectionService) windowContext
+				.get(ESelectionService.class.getName());
+		EPartService partService = (EPartService) windowContext
+				.get(EPartService.class.getName());
+
+		Object selection = new Object();
+		Object selection2 = new Object();
+
+		assertNull(windowService.getSelection());
+		assertNull(partOneImpl.input);
+		assertNull(partTwoImpl.input);
+		assertNull(partThreeImpl.input);
+
+		partOneImpl.setSelection(selection);
+		assertEquals(selection, windowService.getSelection());
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partTwoImpl.input);
+		assertNull(partThreeImpl.input);
+
+		partThreeImpl.setSelection(selection2);
+		assertEquals(selection, windowService.getSelection());
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+
+		partService.activate(partB);
+		assertNull(windowService.getSelection());
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+
+		partService.activate(partC);
+		assertEquals(selection2, windowService.getSelection());
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+	}
+
+	public void testPartOneTracksPartThree() throws Exception {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partA);
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partB);
+		MPart partC = MApplicationFactory.eINSTANCE.createPart();
+		partC.setId("partC");
+		window.getChildren().add(partC);
+		window.setSelectedElement(partA);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		final IEclipseContext partContextA = partA.getContext();
+		IEclipseContext partContextB = partB.getContext();
+		final IEclipseContext partContextC = partC.getContext();
+
+		final TrackingProviderPart partOneImpl = new TrackingProviderPart();
+		ContextInjectionFactory.inject(partOneImpl, partContextA);
+
+		ConsumerPart partTwoImpl = new ConsumerPart();
+		ContextInjectionFactory.inject(partTwoImpl, partContextB);
+
+		ProviderPart partThreeImpl = new ProviderPart();
+		ContextInjectionFactory.inject(partThreeImpl, partContextC);
+
+		Object selection = new Object();
+		Object selection2 = new Object();
+
+		partOneImpl.setSelection(selection);
+		partThreeImpl.setSelection(selection2);
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+
+		// part one tracks down part three. this could just as easily be
+		// fronted by the mediator.addSelectionListener(*)
+		partContextC.runAndTrack(new Runnable() {
+			public void run() {
+				ESelectionService s = (ESelectionService) partContextA
+						.get(ESelectionService.class.getName());
+				partOneImpl.setOtherSelection(s.getSelection("partC"));
+			}
+		});
+
+		assertEquals(selection, partOneImpl.input);
+		assertEquals(selection2, partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+
+		partThreeImpl.setSelection(selection);
+		assertEquals(selection, partOneImpl.input);
+		assertEquals(selection, partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection, partThreeImpl.input);
+
+		partThreeImpl.setSelection(null);
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertNull(partThreeImpl.input);
+	}
+
+	public void testPartOneTracksPartThree2() throws Exception {
+		MApplication application = MApplicationFactory.eINSTANCE
+				.createApplication();
+		MWindow window = MApplicationFactory.eINSTANCE.createWindow();
+		application.getChildren().add(window);
+		application.setSelectedElement(window);
+
+		MPart partA = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partA);
+		MPart partB = MApplicationFactory.eINSTANCE.createPart();
+		window.getChildren().add(partB);
+		MPart partC = MApplicationFactory.eINSTANCE.createPart();
+		partC.setId("partC");
+		window.getChildren().add(partC);
+		window.setSelectedElement(partA);
+
+		initialize(applicationContext, application);
+		getEngine().createGui(window);
+
+		final IEclipseContext partContextA = partA.getContext();
+		IEclipseContext partContextB = partB.getContext();
+		final IEclipseContext partContextC = partC.getContext();
+
+		final TrackingProviderPart partOneImpl = new TrackingProviderPart();
+		ContextInjectionFactory.inject(partOneImpl, partContextA);
+
+		ConsumerPart partTwoImpl = new ConsumerPart();
+		ContextInjectionFactory.inject(partTwoImpl, partContextB);
+
+		ProviderPart partThreeImpl = new ProviderPart();
+		ContextInjectionFactory.inject(partThreeImpl, partContextC);
+
+		Object selection = new Object();
+		Object selection2 = new Object();
+		Object selection3 = new Object();
+
+		partOneImpl.setSelection(selection);
+		partThreeImpl.setSelection(selection2);
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection2, partThreeImpl.input);
+
+		ESelectionService selectionService = (ESelectionService) partContextA
+				.get(ESelectionService.class.getName());
+		selectionService.addSelectionListener(partC.getId(),
+				new ISelectionListener() {
+					public void selectionChanged(MPart part, Object selection) {
+						partOneImpl.setOtherSelection(selection);
+					}
+				});
+
+		partThreeImpl.setSelection(selection3);
+
+		assertEquals(selection, partOneImpl.input);
+		assertEquals(selection3, partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection3, partThreeImpl.input);
+
+		partThreeImpl.setSelection(selection);
+		assertEquals(selection, partOneImpl.input);
+		assertEquals(selection, partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertEquals(selection, partThreeImpl.input);
+
+		partThreeImpl.setSelection(null);
+		assertEquals(selection, partOneImpl.input);
+		assertNull(partOneImpl.otherSelection);
+		assertNull(partTwoImpl.input);
+		assertNull(partThreeImpl.input);
+	}
+
+	private void initialize(IEclipseContext applicationContext,
+			MApplication application) {
+		applicationContext.set(MApplication.class.getName(), application);
+		application.setContext(applicationContext);
+		Workbench.processHierarchy(application);
+		((Notifier) application).eAdapters().add(
+				new UIEventPublisher(applicationContext));
+	}
+
+	static class SelectionListener implements ISelectionListener {
+
+		private MPart part;
+		private Object selection;
+
+		public void reset() {
+			part = null;
+			selection = null;
+		}
+
+		public void selectionChanged(MPart part, Object selection) {
+			this.part = part;
+			this.selection = selection;
+		}
+
+		public MPart getPart() {
+			return part;
+		}
+
+		public Object getSelection() {
+			return selection;
+		}
+
+	}
+}
diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/HeadlessContextPresentationEngine.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/HeadlessContextPresentationEngine.java
index 8b9ac54..a814d54 100644
--- a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/HeadlessContextPresentationEngine.java
+++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/HeadlessContextPresentationEngine.java
@@ -127,8 +127,12 @@
 	 */
 	public Object createGui(MUIElement element, Object parent) {
 		if (element instanceof MContext) {
-			final IEclipseContext parentContext = getParentContext(element);
 			MContext mcontext = (MContext) element;
+			if (mcontext.getContext() != null) {
+				return null;
+			}
+
+			final IEclipseContext parentContext = getParentContext(element);
 			final IEclipseContext createdContext = EclipseContextFactory
 					.create(parentContext, null);
 
@@ -153,6 +157,11 @@
 					contribution.setObject(clientObject);
 				}
 			}
+
+			if (parentContext.getLocal(IContextConstants.ACTIVE_CHILD) == null) {
+				parentContext.set(IContextConstants.ACTIVE_CHILD,
+						createdContext);
+			}
 		}
 
 		if (element instanceof MPartStack) {
@@ -177,8 +186,11 @@
 						IEclipseContext childContext = ((MContext) child)
 								.getContext();
 						IEclipseContext parentContext = getParentContext((MUIElement) child);
-						parentContext.set(IContextConstants.ACTIVE_CHILD,
-								childContext);
+						if (parentContext
+								.getLocal(IContextConstants.ACTIVE_CHILD) == null) {
+							parentContext.set(IContextConstants.ACTIVE_CHILD,
+									childContext);
+						}
 					}
 				}
 			}
diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/StartupTestSuite.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/StartupTestSuite.java
index a0f6ea5..bbdd713 100644
--- a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/StartupTestSuite.java
+++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/StartupTestSuite.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009 IBM Corporation and others.
+ * Copyright (c) 2009, 2010 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,6 +21,8 @@
 
 		suite.addTestSuite(EModelServiceFindTest.class);
 		suite.addTestSuite(EPartServiceTest.class);
+		suite.addTestSuite(ESelectionServiceTest.class);
+
 		suite.addTestSuite(HeadlessContactsDemoTest.class);
 		suite.addTestSuite(HeadlessPhotoDemoTest.class);