Bug 305707 - add a way to contribute object providers to dependency injection
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/ContextChangeEvent.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/ContextChangeEvent.java
index 3aabd9f..fe66ece 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/ContextChangeEvent.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/ContextChangeEvent.java
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.e4.core.services.context;
 
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 
 /**
  * An event describing a change to an {@link IEclipseContext}. The following types of events are
@@ -67,7 +66,7 @@
 	public static final int UPDATE = 5;
 
 	private Object[] args;
-	private IObjectProvider context;
+	private IEclipseContext context;
 	private int eventType;
 	private String key;
 
@@ -81,7 +80,7 @@
 	 * @param args
 	 * @param name
 	 */
-	ContextChangeEvent(IObjectProvider context, int eventType, Object[] args, String name,
+	ContextChangeEvent(IEclipseContext context, int eventType, Object[] args, String name,
 			Object oldValue) {
 		this.context = context;
 		this.key = name;
@@ -105,7 +104,7 @@
 	 * 
 	 * @return the context where the change occurred
 	 */
-	public IObjectProvider getContext() {
+	public IEclipseContext getContext() {
 		return context;
 	}
 
@@ -135,8 +134,8 @@
 	public int hashCode() {
 		final int prime = 31;
 		int result = 1;
-		if ((eventType == DISPOSE) || (eventType == UNINJECTED))
-			result = prime * result + ((context == null) ? 0 : context.hashCode());
+		// if ((eventType == DISPOSE) || (eventType == UNINJECTED))
+		// result = prime * result + ((context == null) ? 0 : context.hashCode());
 		result = prime * result + eventType;
 		result = prime * result + ((key == null) ? 0 : key.hashCode());
 		return result;
@@ -151,13 +150,13 @@
 			return false;
 		ContextChangeEvent other = (ContextChangeEvent) obj;
 
-		if ((eventType == DISPOSE) || (eventType == UNINJECTED)) {
-			if (context == null) {
-				if (other.context != null)
-					return false;
-			} else if (!context.equals(other.context))
-				return false;
-		}
+		// if ((eventType == DISPOSE) || (eventType == UNINJECTED)) {
+		// if (context == null) {
+		// if (other.context != null)
+		// return false;
+		// } else if (!context.equals(other.context))
+		// return false;
+		// }
 
 		if (eventType != other.eventType)
 			return false;
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/EclipseContextFactory.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/EclipseContextFactory.java
index cf16ce2..5f1cf5b 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/EclipseContextFactory.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/EclipseContextFactory.java
@@ -15,9 +15,7 @@
 import org.eclipse.e4.core.services.context.spi.IContextConstants;
 import org.eclipse.e4.core.services.context.spi.IEclipseContextStrategy;
 import org.eclipse.e4.core.services.context.spi.ILookupStrategy;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 import org.eclipse.e4.core.services.internal.context.EclipseContext;
-import org.eclipse.e4.core.services.internal.context.ObjectProviderContext;
 import org.eclipse.e4.internal.core.services.osgi.OSGiContextStrategy;
 import org.osgi.framework.BundleContext;
 
@@ -97,12 +95,6 @@
 	 */
 	public static ContextChangeEvent createContextEvent(IEclipseContext context, int eventType,
 			Object[] args, String name, Object oldValue) {
-		return new ContextChangeEvent(new ObjectProviderContext(context), eventType, args, name,
-				oldValue);
-	}
-
-	public static ContextChangeEvent createContextEvent(IObjectProvider provider, int eventType,
-			Object[] args, String name, Object oldValue) {
-		return new ContextChangeEvent(provider, eventType, args, name, oldValue);
+		return new ContextChangeEvent(context, eventType, args, name, oldValue);
 	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/spi/ContextInjectionFactory.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/spi/ContextInjectionFactory.java
index 82c7094..a85bd43 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/spi/ContextInjectionFactory.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/spi/ContextInjectionFactory.java
@@ -16,11 +16,11 @@
 import org.eclipse.e4.core.services.IDisposable;
 import org.eclipse.e4.core.services.context.IEclipseContext;
 import org.eclipse.e4.core.services.context.IEclipseContextAware;
+import org.eclipse.e4.core.services.injector.AbstractObjectSupplier;
 import org.eclipse.e4.core.services.injector.IInjector;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 import org.eclipse.e4.core.services.injector.InjectorFactory;
+import org.eclipse.e4.core.services.internal.context.ContextObjectSupplier;
 import org.eclipse.e4.core.services.internal.context.EclipseContext;
-import org.eclipse.e4.core.services.internal.context.ObjectProviderContext;
 
 /**
  * An injection factory is used to inject data and services from a context into a domain object. The
@@ -93,8 +93,9 @@
 	 * @return Returns the injected object
 	 */
 	static public Object inject(Object object, IEclipseContext context) {
-		IObjectProvider provider = ObjectProviderContext.getObjectProvider(context);
-		injector.inject(object, provider);
+		AbstractObjectSupplier supplier = ContextObjectSupplier.getObjectSupplier(context,
+				injector);
+		injector.inject(object, supplier);
 		return object;
 	}
 
@@ -115,8 +116,9 @@
 	 */
 	static public Object invoke(Object object, String methodName, IEclipseContext context)
 			throws InvocationTargetException, CoreException {
-		IObjectProvider provider = ObjectProviderContext.getObjectProvider(context);
-		return injector.invoke(object, methodName, provider);
+		AbstractObjectSupplier supplier = ContextObjectSupplier.getObjectSupplier(context,
+				injector);
+		return injector.invoke(object, methodName, supplier);
 	}
 
 	/**
@@ -136,8 +138,9 @@
 	 */
 	static public Object invoke(Object object, String methodName, IEclipseContext context,
 			Object defaultValue) throws InvocationTargetException {
-		IObjectProvider provider = ObjectProviderContext.getObjectProvider(context);
-		return injector.invoke(object, methodName, defaultValue, provider);
+		AbstractObjectSupplier supplier = ContextObjectSupplier.getObjectSupplier(context,
+				injector);
+		return injector.invoke(object, methodName, defaultValue, supplier);
 	}
 
 	/**
@@ -169,7 +172,8 @@
 	 */
 	static public Object make(Class clazz, final IEclipseContext context)
 			throws InvocationTargetException, InstantiationException {
-		IObjectProvider provider = ObjectProviderContext.getObjectProvider(context);
-		return injector.make(clazz, provider);
+		AbstractObjectSupplier supplier = ContextObjectSupplier.getObjectSupplier(context,
+				injector);
+		return injector.make(clazz, supplier);
 	}
 }
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/AbstractObjectSupplier.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/AbstractObjectSupplier.java
new file mode 100644
index 0000000..d7d24d1
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/AbstractObjectSupplier.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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.core.services.injector;
+
+/**
+ * This interface describes an "object supplier" - something that knows how to instantiate objects
+ * corresponding to the descriptor. NOTE: This is a preliminary form; this API will change.
+ */
+abstract public class AbstractObjectSupplier {
+
+	final protected IInjector injector;
+
+	// TBD remove?
+	abstract public Object get(IObjectDescriptor descriptor, IRequestor requestor);
+
+	abstract public Object[] get(IObjectDescriptor[] descriptors, IRequestor requestor);
+
+	public AbstractObjectSupplier(IInjector injector) {
+		this.injector = injector;
+	}
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IBinding.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IBinding.java
new file mode 100644
index 0000000..72476a4
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IBinding.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.core.services.injector;
+
+// TBD should this be an abstract base class?
+/**
+ * Describes binding between object description and its implementation to be used by the dependency
+ * injection.
+ * 
+ */
+public interface IBinding {
+
+	public IBinding named(String name);
+
+	public IBinding implementedBy(Class<?> clazz);
+
+	public Class<?> getDescribedClass();
+
+	public String getQualifierName();
+
+	public Class<?> getImplementationClass();
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IInjector.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IInjector.java
index 62c75b8..d6a67c7 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IInjector.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IInjector.java
@@ -23,17 +23,32 @@
  */
 public interface IInjector {
 
-	public boolean inject(Object object, IObjectProvider objectProvider);
+	final public static Object NOT_A_VALUE = new Object();
 
-	public Object make(Class clazz, IObjectProvider objectProvider)
-			throws InvocationTargetException, InstantiationException;
+	public boolean inject(Object object, AbstractObjectSupplier objectSupplier);
 
-	public Object invoke(Object object, String methodName, IObjectProvider objectProvider)
+	public boolean uninject(Object object, AbstractObjectSupplier objectSupplier);
+
+	public Object invoke(Object object, String methodName, AbstractObjectSupplier objectSupplier)
 			throws InvocationTargetException, CoreException;
 
 	public Object invoke(Object object, String methodName, Object defaultValue,
-			IObjectProvider objectProvider) throws InvocationTargetException;
+			AbstractObjectSupplier objectSupplier) throws InvocationTargetException;
 
-	public boolean injectStatic(Class clazz, IObjectProvider objectProvider);
+	public Object make(Class<?> clazz, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, InstantiationException;
+
+	public Object make(IObjectDescriptor descriptor, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, InstantiationException;
+
+	public boolean injectStatic(Class<?> clazz, AbstractObjectSupplier objectSupplier);
+
+	public boolean update(IRequestor[] requestors, AbstractObjectSupplier objectSupplier);
+
+	public boolean disposed(AbstractObjectSupplier objectSupplier);
+
+	public IBinding addBinding(Class<?> clazz);
+
+	public IBinding addBinding(IBinding binding);
 
 }
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectDescriptor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectDescriptor.java
new file mode 100644
index 0000000..c6040af
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectDescriptor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.core.services.injector;
+
+import java.lang.reflect.Type;
+
+/**
+ * NOTE: This is a preliminary form; this API will change.
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IObjectDescriptor {
+
+	// TBD rename getDesiredClass()
+	// TBD is this needed if we can get a Type?
+	public Class<?> getElementClass();
+
+	public Type getElementType();
+
+	public boolean isOptional();
+
+	public boolean hasQualifier(String qualifier);
+
+	public String[] getQualifiers();
+
+	public String getQualifierValue(String qualifier);
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectProvider.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectProvider.java
deleted file mode 100644
index 3b3323f..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IObjectProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*******************************************************************************
- * 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.core.services.injector;
-
-import org.eclipse.e4.core.services.context.IRunAndTrack;
-
-/**
- * This interface describes an "object provider" - something that knows how to instantiate objects
- * corresponding to the key. NOTE: This is a preliminary form; this API will change.
- */
-public interface IObjectProvider {
-
-	public boolean containsKey(ObjectDescriptor key);
-
-	public Object get(ObjectDescriptor key);
-
-	// TBD replace this with events specific to injection, not context
-	public void runAndTrack(final IRunAndTrack runnable, Object[] args);
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IRequestor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IRequestor.java
new file mode 100644
index 0000000..5e64c9d
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/IRequestor.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.core.services.injector;
+
+// TBD this is really a "feedback" object. 
+/**
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface IRequestor {
+
+	/**
+	 * The injected object that initiated this request
+	 */
+	public Object getRequestingObject();
+
+	/**
+	 * Determines if the requestor wants to be called whenever one of the dependent object changes.
+	 */
+	public boolean shouldTrack();
+
+	public boolean shouldGroupUpdates();
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptorFactory.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptorFactory.java
new file mode 100644
index 0000000..c2ef932
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptorFactory.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.core.services.injector;
+
+import java.lang.reflect.Type;
+import javax.inject.Named;
+import org.eclipse.e4.core.services.internal.context.ObjectDescriptor;
+
+/**
+ * NOTE: This is a preliminary form; this API will change.
+ * 
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+final public class ObjectDescriptorFactory {
+
+	static final private String named = Named.class.getName();
+
+	private ObjectDescriptorFactory() {
+		// prevents instantiation
+	}
+
+	static public IObjectDescriptor make(Class<?> clazz, boolean optional) {
+		return new ObjectDescriptor(clazz, null, null, optional);
+	}
+
+	static public IObjectDescriptor make(Type type, boolean optional) {
+		return new ObjectDescriptor(type, null, null, optional);
+	}
+
+	static public IObjectDescriptor make(String name, boolean optional) {
+		return new ObjectDescriptor(null, new String[] { named }, new String[] { name }, optional);
+	}
+
+	static public IObjectDescriptor make(Class<?> clazz, String name, boolean optional) {
+		if (name == null)
+			return make(clazz, optional);
+		return new ObjectDescriptor(clazz, new String[] { named }, new String[] { name }, optional);
+	}
+
+	static public IObjectDescriptor make(Type type, String name, boolean optional) {
+		if (name == null)
+			return make(type, optional);
+		return new ObjectDescriptor(type, new String[] { named }, new String[] { name }, optional);
+	}
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/annotations/AnnotationsSupport.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/annotations/AnnotationsSupport.java
index fc007da..2fbdef5 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/annotations/AnnotationsSupport.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/annotations/AnnotationsSupport.java
@@ -13,7 +13,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
+import java.lang.reflect.Type;
 import org.eclipse.e4.core.services.internal.context.InjectionProperties;
 
 /**
@@ -25,28 +25,28 @@
 		// placeholder
 	}
 
-	public InjectionProperties getInjectProperties(Field field, IObjectProvider context) {
+	public InjectionProperties getInjectProperties(Field field) {
 		return new InjectionProperties(false, null, false);
 	}
 
-	public InjectionProperties getInjectProperties(Method method, IObjectProvider context) {
+	public InjectionProperties getInjectProperties(Method method) {
 		return new InjectionProperties(false, null, false);
 	}
 
-	public InjectionProperties getInjectProperties(Constructor constructor, IObjectProvider context) {
+	public InjectionProperties getInjectProperties(Constructor constructor) {
 		return new InjectionProperties(true, null, false);
 	}
 
-	public InjectionProperties[] getInjectParamsProperties(Constructor constructor,
-			IObjectProvider context) {
-		Class[] params = constructor.getParameterTypes();
+	public InjectionProperties[] getInjectParamsProperties(Constructor constructor) {
+		Type[] params = constructor.getGenericParameterTypes();
+
 		InjectionProperties[] result = new InjectionProperties[params.length];
 		for (int i = 0; i < result.length; i++)
 			result[i] = new InjectionProperties(false, null, false);
 		return result;
 	}
 
-	public InjectionProperties[] getInjectParamProperties(Method method, IObjectProvider context) {
+	public InjectionProperties[] getInjectParamProperties(Method method) {
 		Class[] params = method.getParameterTypes();
 		InjectionProperties[] result = new InjectionProperties[params.length];
 		for (int i = 0; i < result.length; i++)
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Binding.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Binding.java
new file mode 100644
index 0000000..192af5b
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Binding.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import org.eclipse.e4.core.services.injector.IBinding;
+import org.eclipse.e4.core.services.injector.IInjector;
+
+public class Binding implements IBinding {
+
+	final private Class<?> clazz;
+	final private IInjector injector;
+
+	private Class<?> implementationClazz;
+	private String qualifierName;
+
+	public Binding(Class<?> clazz, IInjector injector) {
+		this.clazz = clazz;
+		this.injector = injector;
+	}
+
+	private Binding(Binding source) {
+		this.clazz = source.clazz;
+		this.injector = source.injector;
+		this.implementationClazz = source.implementationClazz;
+		this.qualifierName = source.qualifierName;
+	}
+
+	public IBinding named(String name) {
+		Binding binding = new Binding(this);
+		binding.qualifierName = name;
+		injector.addBinding(binding);
+		return binding;
+	}
+
+	public IBinding implementedBy(Class<?> clazz) {
+		Binding binding = new Binding(this);
+		binding.implementationClazz = clazz;
+		injector.addBinding(binding);
+		return binding;
+	}
+
+	public Class<?> getDescribedClass() {
+		return clazz;
+	}
+
+	public String getQualifierName() {
+		return qualifierName;
+	}
+
+	public Class<?> getImplementationClass() {
+		if (implementationClazz != null)
+			return implementationClazz;
+		return clazz;
+	}
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Computation.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Computation.java
index c71570b..59afe26 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Computation.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Computation.java
@@ -18,7 +18,6 @@
 import java.util.Set;
 import org.eclipse.e4.core.services.context.ContextChangeEvent;
 import org.eclipse.e4.core.services.context.IEclipseContext;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 import org.eclipse.e4.core.services.internal.context.EclipseContext.Scheduled;
 
 abstract class Computation {
@@ -52,8 +51,7 @@
 	public abstract boolean equals(Object arg0);
 
 	final void handleInvalid(ContextChangeEvent event, List<Scheduled> scheduled) {
-		IObjectProvider provider = event.getContext();
-		IEclipseContext context = ((ObjectProviderContext) provider).getContext();
+		IEclipseContext context = event.getContext();
 
 		String name = event.getName();
 		Set<String> names = dependencies.get(context);
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ConstructorRequestor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ConstructorRequestor.java
new file mode 100644
index 0000000..1407b0c
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ConstructorRequestor.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.ObjectDescriptorFactory;
+
+public class ConstructorRequestor extends Requestor {
+
+	final private Constructor<?> constructor;
+
+	public ConstructorRequestor(Constructor<?> constructor) {
+		// TBD make an integer update types? 0 - static , 1 - normal, 2 - grouped?
+		super(null, false /* do not track */, false /* N/A: no updates */, false /* mandatory */);
+		this.constructor = constructor;
+	}
+
+	public Object execute() throws InvocationTargetException, InstantiationException {
+		return callConstructor(constructor, actualArgs);
+	}
+
+	@Override
+	public IObjectDescriptor[] getDependentObjects() {
+		// Class[] parameterTypes = constructor.getParameterTypes();
+		Type[] parameterTypes = constructor.getGenericParameterTypes();
+		InjectionProperties[] properties = annotationSupport.getInjectParamsProperties(constructor);
+		IObjectDescriptor[] descriptors = new IObjectDescriptor[properties.length];
+		for (int i = 0; i < properties.length; i++) {
+			descriptors[i] = ObjectDescriptorFactory.make(parameterTypes[i], properties[i]
+					.getPropertyName(), properties[i].isOptional());
+		}
+		return descriptors;
+	}
+
+	private Object callConstructor(Constructor<?> constructor, Object[] args)
+			throws InvocationTargetException, InstantiationException {
+		Object result = null;
+		boolean wasAccessible = true;
+		if (!constructor.isAccessible()) {
+			constructor.setAccessible(true);
+			wasAccessible = false;
+		}
+		try {
+			result = constructor.newInstance(args);
+		} catch (IllegalArgumentException e) {
+			// should not happen, is checked at the start of this method
+			logError(constructor, e);
+			return null;
+		} catch (IllegalAccessException e) {
+			// should not happen as we set constructor to be accessible
+			logError(constructor, e);
+			return null;
+		} finally {
+			if (!wasAccessible)
+				constructor.setAccessible(false);
+		}
+		return result;
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ContextObjectSupplier.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ContextObjectSupplier.java
new file mode 100644
index 0000000..8fbb8e2
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ContextObjectSupplier.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import javax.inject.Named;
+import org.eclipse.e4.core.services.context.ContextChangeEvent;
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.core.services.context.IRunAndTrack;
+import org.eclipse.e4.core.services.injector.AbstractObjectSupplier;
+import org.eclipse.e4.core.services.injector.IInjector;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.IRequestor;
+
+public class ContextObjectSupplier extends AbstractObjectSupplier {
+
+	static private class ContextInjectionListener implements IRunAndTrackObject {
+
+		final private Object[] result;
+		final private String[] keys;
+		final private IInjector injector;
+		final private IRequestor requestor;
+		final private AbstractObjectSupplier supplier;
+		final private IEclipseContext context;
+
+		public ContextInjectionListener(IEclipseContext context, Object[] result, String[] keys,
+				IInjector injector, IRequestor requestor, AbstractObjectSupplier supplier) {
+			this.result = result;
+			this.keys = keys;
+			this.injector = injector;
+			this.requestor = requestor;
+			this.supplier = supplier;
+			this.context = context;
+		}
+
+		public boolean notify(ContextChangeEvent event) {
+			if (event.getEventType() == ContextChangeEvent.INITIAL) {
+				// needs to be done inside runnable to establish dependencies
+				for (int i = 0; i < keys.length; i++) {
+					if (keys[i] == null)
+						continue;
+					if (context.containsKey(keys[i]))
+						result[i] = context.get(keys[i]);
+					else
+						result[i] = IInjector.NOT_A_VALUE; // TBD make sure this still creates
+															// dependency on the key
+				}
+			} else if (event.getEventType() == ContextChangeEvent.DISPOSE) {
+				injector.disposed(supplier);
+				return false;
+			} else if (event.getEventType() == ContextChangeEvent.UNINJECTED) {
+				injector.uninject(event.getArguments()[0], supplier);
+				return false;
+			} else
+				injector.update(new IRequestor[] { requestor }, supplier);
+			return true;
+		}
+
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + ((context == null) ? 0 : context.hashCode());
+			result = prime * result + ((injector == null) ? 0 : injector.hashCode());
+			result = prime * result + ((requestor == null) ? 0 : requestor.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			ContextInjectionListener other = (ContextInjectionListener) obj;
+			if (context == null) {
+				if (other.context != null)
+					return false;
+			} else if (!context.equals(other.context))
+				return false;
+			if (injector == null) {
+				if (other.injector != null)
+					return false;
+			} else if (!injector.equals(other.injector))
+				return false;
+			if (requestor == null) {
+				if (other.requestor != null)
+					return false;
+			} else if (!requestor.equals(other.requestor))
+				return false;
+			return true;
+		}
+
+		public Object getObject() {
+			// XXX remove?
+			// TODO Auto-generated method stub
+			return null;
+		}
+
+		public boolean batchProcess() {
+			return requestor.shouldGroupUpdates();
+		}
+	}
+
+	final static private String ECLIPSE_CONTEXT_NAME = IEclipseContext.class.getName();
+	final private IEclipseContext context;
+
+	public ContextObjectSupplier(IEclipseContext context, IInjector injector) {
+		super(injector);
+		this.context = context;
+	}
+
+	public IEclipseContext getContext() {
+		return context;
+	}
+
+	@Override
+	public Object get(IObjectDescriptor descriptor, IRequestor requestor) {
+		// This method is rarely or never used on the primary supplier
+		if (descriptor == null)
+			return IInjector.NOT_A_VALUE;
+		Object[] result = get(new IObjectDescriptor[] { descriptor }, requestor);
+		if (result == null)
+			return null;
+		return result[0];
+	}
+
+	@Override
+	public Object[] get(IObjectDescriptor[] descriptors, final IRequestor requestor) {
+		final Object[] result = new Object[descriptors.length];
+		final String[] keys = new String[descriptors.length];
+
+		for (int i = 0; i < descriptors.length; i++) {
+			keys[i] = (descriptors[i] == null) ? null : getKey(descriptors[i]);
+			if (ECLIPSE_CONTEXT_NAME.equals(keys[i])) {
+				result[i] = context;
+				keys[i] = null;
+			}
+		}
+
+		if (requestor != null && requestor.shouldTrack()) { // only track if requested
+			IRunAndTrack trackable = new ContextInjectionListener(context, result, keys, injector,
+					requestor, this);
+			context.runAndTrack(trackable, null);
+		} else {
+			for (int i = 0; i < descriptors.length; i++) {
+				if (keys[i] == null)
+					continue;
+				if (context.containsKey(keys[i]))
+					result[i] = context.get(keys[i]);
+				else
+					result[i] = IInjector.NOT_A_VALUE;
+			}
+		}
+		return result;
+	}
+
+	private String getKey(IObjectDescriptor descriptor) {
+		if (descriptor.hasQualifier(Named.class.getName()))
+			return descriptor.getQualifierValue(Named.class.getName());
+		Class<?> elementClass = descriptor.getElementClass();
+		if (elementClass != null)
+			return elementClass.getName();
+		return null;
+	}
+
+	static public ContextObjectSupplier getObjectSupplier(IEclipseContext context,
+			IInjector injector) {
+		String key = ContextObjectSupplier.class.getName();
+		if (context.containsKey(key, true))
+			return (ContextObjectSupplier) context.get(key);
+		ContextObjectSupplier objectSupplier = new ContextObjectSupplier(context, injector);
+		context.set(key, objectSupplier);
+		return objectSupplier;
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
index 73b280d..0811591 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
@@ -151,8 +151,7 @@
 				if ((eventType == ContextChangeEvent.ADDED)
 						|| (eventType == ContextChangeEvent.REMOVED)) {
 					cachedEvent = event;
-					EclipseContext eventsContext = (EclipseContext) ((ObjectProviderContext) event
-							.getContext()).getContext();
+					EclipseContext eventsContext = (EclipseContext) event.getContext();
 					eventsContext.addWaiting(this);
 					// eventsContext.getRoot().waiting.add(this);
 					return true;
@@ -171,8 +170,7 @@
 			} finally {
 				currentComputation.set(oldComputation);
 			}
-			EclipseContext eventsContext = (EclipseContext) ((ObjectProviderContext) event
-					.getContext()).getContext();
+			EclipseContext eventsContext = (EclipseContext) event.getContext();
 			if (result)
 				startListening(eventsContext);
 			else
@@ -407,7 +405,7 @@
 	 * The given name has been modified or removed in this context. Invalidate all local value
 	 * computations and listeners that depend on this name.
 	 */
-	private void invalidate(String name, int eventType, Object oldValue, List<Scheduled> scheduled) {
+	public void invalidate(String name, int eventType, Object oldValue, List<Scheduled> scheduled) {
 		if (EclipseContext.DEBUG)
 			System.out.println("invalidating " + this + ',' + name); //$NON-NLS-1$
 		removeLocalValueComputations(name);
@@ -583,18 +581,11 @@
 	public void removeListenersTo(Object object) {
 		if (object == null)
 			return;
-		synchronized (listeners) {
-			ContextChangeEvent event = EclipseContextFactory.createContextEvent(this,
-					ContextChangeEvent.UNINJECTED, null, null, null);
-			for (Iterator<Computation> i = listeners.keySet().iterator(); i.hasNext();) {
-				Computation computation = i.next();
-				if (computation instanceof TrackableComputationExt) {
-					if (object == ((TrackableComputationExt) computation).getObject()) {
-						((IRunAndTrack) computation).notify(event);
-						i.remove();
-					}
-				}
-			}
+		Computation[] ls = listeners.keySet().toArray(new Computation[listeners.size()]);
+		ContextChangeEvent event = EclipseContextFactory.createContextEvent(this,
+				ContextChangeEvent.UNINJECTED, new Object[] { object }, null, null);
+		for (Computation computation : ls) {
+			((IRunAndTrack) computation).notify(event);
 		}
 	}
 
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/FieldRequestor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/FieldRequestor.java
new file mode 100644
index 0000000..1d07427
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/FieldRequestor.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.ObjectDescriptorFactory;
+
+public class FieldRequestor extends Requestor {
+
+	final private Field field;
+
+	public FieldRequestor(Field field, Object requestingObject, boolean track,
+			boolean groupUpdates, boolean optional) {
+		super(requestingObject, track, groupUpdates, optional);
+		this.field = field;
+	}
+
+	public Object execute() throws InvocationTargetException, InstantiationException {
+		setField(field, actualArgs[0]);
+		return null;
+	}
+
+	@Override
+	public IObjectDescriptor[] getDependentObjects() {
+		InjectionProperties properties = annotationSupport.getInjectProperties(field);
+		IObjectDescriptor objectDescriptor = ObjectDescriptorFactory.make(field.getGenericType(),
+				properties.getPropertyName(), properties.isOptional());
+		return new IObjectDescriptor[] { objectDescriptor };
+	}
+
+	private boolean setField(Field field, Object value) {
+		Object userObject = getRequestingObject();
+		if (userObject == null)
+			return false;
+		boolean wasAccessible = true;
+		if (!field.isAccessible()) {
+			field.setAccessible(true);
+			wasAccessible = false;
+		}
+		try {
+			field.set(userObject, value);
+		} catch (IllegalArgumentException e) {
+			logError(field, e);
+			return false;
+		} catch (IllegalAccessException e) {
+			logError(field, e);
+			return false;
+		} finally {
+			if (!wasAccessible)
+				field.setAccessible(false);
+		}
+		return true;
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionAbstract.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionAbstract.java
deleted file mode 100644
index c2f7435..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionAbstract.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import java.lang.ref.WeakReference;
-import org.eclipse.e4.core.services.context.ContextChangeEvent;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-import org.eclipse.e4.core.services.internal.annotations.AnnotationsSupport;
-
-abstract public class InjectionAbstract implements IRunAndTrackObject {
-
-	final static protected Object NOT_A_VALUE = new Object();
-
-	final protected WeakReference userObjectRef;
-	final protected AnnotationsSupport annotationSupport;
-	final protected IObjectProvider primarySupplier;
-
-	protected boolean optional = false;
-	final private boolean batchProcess;
-
-	abstract public boolean notify(ContextChangeEvent event);
-
-	public InjectionAbstract(Object userObject, IObjectProvider primarySupplier,
-			boolean batchProcess) {
-		userObjectRef = new WeakReference(userObject);
-		// plug-in class that gets replaced in Java 1.5+
-		annotationSupport = new AnnotationsSupport(); // TBD this should be a static util class
-		this.primarySupplier = primarySupplier;
-		this.batchProcess = batchProcess;
-	}
-
-	public Object getObject() {
-		if (userObjectRef == null)
-			return null;
-		return userObjectRef.get();
-	}
-
-	protected boolean injectNulls(int eventType, IObjectProvider changed) {
-		if ((eventType != ContextChangeEvent.UNINJECTED)
-				&& (eventType != ContextChangeEvent.DISPOSE))
-			return false;
-		return (changed.equals(primarySupplier));
-	}
-
-	protected boolean ignoreMissing(int eventType, IObjectProvider changed) {
-		if (eventType == ContextChangeEvent.REMOVED)
-			return true;
-		if ((eventType != ContextChangeEvent.UNINJECTED)
-				&& (eventType != ContextChangeEvent.DISPOSE))
-			return false;
-		return (changed.equals(primarySupplier));
-	}
-
-	protected Object getValue(ObjectDescriptor objectDescriptor, InjectionProperties properties,
-			Class parameterType, boolean ignoreMissing, boolean injectWithNulls) {
-		// 1) if we have a provider, use it
-		Object provider = properties.getProvider();
-		if (provider != null)
-			return provider;
-
-		// 2) if we have the key in the context
-		if (primarySupplier.containsKey(objectDescriptor)) {
-			if (injectWithNulls)
-				return null;
-			Object value = primarySupplier.get(objectDescriptor);
-			if (value == null)
-				return value;
-			if (parameterType.isAssignableFrom(value.getClass()))
-				return value;
-		}
-
-		// 3) can we ignore this argument?
-		if (ignoreMissing || properties.isOptional())
-			return null;
-
-		if (!optional) {
-			String msg = "Unable to find value for \"" + objectDescriptor.toString() + "\"";
-			throw new IllegalArgumentException(msg);
-		}
-		return NOT_A_VALUE;
-	}
-
-	protected void logError(Object destination, Exception e) {
-		String msg = "Injection failed " + destination.toString();
-		logError(msg, e);
-	}
-
-	protected void logError(String msg, Exception e) {
-		System.out.println(msg); //$NON-NLS-1$
-		if (e != null)
-			e.printStackTrace();
-		// TBD convert this into real logging
-		// String msg = NLS.bind("Injection failed", destination.toString());
-		// RuntimeLog.log(new Status(IStatus.WARNING,
-		// IRuntimeConstants.PI_COMMON, 0, msg, e));
-	}
-
-	public boolean batchProcess() {
-		return batchProcess;
-	}
-
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionClass.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionClass.java
deleted file mode 100644
index aa79d6a..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionClass.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Iterator;
-import org.eclipse.e4.core.services.IDisposable;
-import org.eclipse.e4.core.services.context.ContextChangeEvent;
-import org.eclipse.e4.core.services.context.IEclipseContext;
-import org.eclipse.e4.core.services.context.spi.ContextInjectionFactory;
-import org.eclipse.e4.core.services.context.spi.IContextConstants;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-
-public class InjectionClass extends InjectionAbstract {
-
-	final static private String JAVA_OBJECT = "java.lang.Object"; //$NON-NLS-1$
-
-	public InjectionClass(Object userObject, IObjectProvider primarySupplier) {
-		super(userObject, primarySupplier, false);
-	}
-
-	public boolean notify(ContextChangeEvent event) {
-		Object object = getObject();
-		if (object == null)
-			return false;
-		int eventType = event.getEventType();
-		if (eventType == ContextChangeEvent.DISPOSE) {
-			if (object instanceof IDisposable)
-				((IDisposable) object).dispose();
-			processPreDestory(object, object.getClass(), new ArrayList(5));
-			return false;
-		}
-		if (eventType == ContextChangeEvent.INITIAL) {
-			processPostConstruct(object, object.getClass(), new ArrayList(5));
-		}
-		IObjectProvider context = event.getContext();
-		// pseudo-dependency to create a link
-		ObjectDescriptor desc = ObjectDescriptor.make("e4_valid_context");
-		context.get(desc);
-		return true;
-	}
-
-	private void processPostConstruct(Object userObject, Class objectClass, ArrayList classHierarchy) {
-		Class superClass = objectClass.getSuperclass();
-		if (superClass != null && !superClass.getName().equals(JAVA_OBJECT)) {
-			classHierarchy.add(objectClass);
-			processPostConstruct(userObject, superClass, classHierarchy);
-			classHierarchy.remove(objectClass);
-		}
-		Method[] methods = objectClass.getDeclaredMethods();
-		for (int i = 0; i < methods.length; i++) {
-			Method method = methods[i];
-			if (!isPostConstruct(method))
-				continue;
-			if (!isOverridden(method, classHierarchy)) {
-				InjectionMethod methodInvoke = new InjectionMethod(getObject(), primarySupplier,
-						method, false);
-				try {
-					methodInvoke.invoke(false, false);
-				} catch (InjectionException e) {
-					// TBD log
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-
-	// TBD simplify this: only one non-annotation and one "implements IInitializable"?
-	/**
-	 * Returns whether the given method is a post-construction process method, as defined by the
-	 * class comment of {@link ContextInjectionFactory}.
-	 */
-	private boolean isPostConstruct(Method method) {
-		boolean isPostConstruct = annotationSupport.isPostConstruct(method);
-		if (isPostConstruct)
-			return true;
-		if (!method.getName().equals(IContextConstants.INJECTION_SET_CONTEXT_METHOD))
-			return false;
-		Class[] parms = method.getParameterTypes();
-		if (parms.length == 0)
-			return true;
-		if (parms.length == 1 && parms[0].equals(IEclipseContext.class))
-			return true;
-		return false;
-	}
-
-	private void processPreDestory(Object userObject, Class objectClass, ArrayList classHierarchy) {
-		Class superClass = objectClass.getSuperclass();
-		if (superClass != null && !superClass.getName().equals(JAVA_OBJECT)) {
-			classHierarchy.add(objectClass);
-			processPreDestory(userObject, superClass, classHierarchy);
-			classHierarchy.remove(objectClass);
-		}
-		Method[] methods = objectClass.getDeclaredMethods();
-		for (int i = 0; i < methods.length; i++) {
-			Method method = methods[i];
-			if (method.getParameterTypes().length > 0) // TBD why?
-				continue;
-			if (!annotationSupport.isPreDestory(method))
-				continue;
-			if (!isOverridden(method, classHierarchy)) {
-				InjectionMethod methodInvoke = new InjectionMethod(getObject(), primarySupplier,
-						method, false);
-				try {
-					methodInvoke.invoke(false, false);
-				} catch (InjectionException e) {
-					// TBD log
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-
-	// TBD move into the base class? For @PostConstruct?
-	/**
-	 * Checks if a given method is overridden with an injectable method.
-	 */
-	private boolean isOverridden(Method method, ArrayList classHierarchy) {
-		int modifiers = method.getModifiers();
-		if (Modifier.isPrivate(modifiers))
-			return false;
-		if (Modifier.isStatic(modifiers))
-			return false;
-		// method is not private if we reached this line, check not(public OR protected)
-		boolean isDefault = !(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers));
-
-		for (Iterator i = classHierarchy.iterator(); i.hasNext();) {
-			Class subClass = (Class) i.next();
-			Method override = null;
-			try {
-				override = subClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
-			} catch (SecurityException e) {
-				continue;
-			} catch (NoSuchMethodException e) {
-				continue; // this is the desired outcome
-			}
-			if (override != null) {
-				if (isDefault) { // must be in the same package to override
-					Package originalPackage = method.getDeclaringClass().getPackage();
-					Package overridePackage = subClass.getPackage();
-
-					if (originalPackage == null && overridePackage == null)
-						return true;
-					if (originalPackage == null || overridePackage == null)
-						return false;
-					if (originalPackage.equals(overridePackage))
-						return true;
-				} else
-					return true;
-			}
-		}
-		return false;
-	}
-
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionConstructor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionConstructor.java
deleted file mode 100644
index efaf0b2..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionConstructor.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import org.eclipse.e4.core.services.context.ContextChangeEvent;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-
-/**
- * Collection of static methods that deal with reflection-based injection at a low level.
- */
-public class InjectionConstructor extends InjectionAbstract {
-
-	private final Constructor constructor;
-
-	public InjectionConstructor(Object userObject, IObjectProvider primarySupplier,
-			Constructor constructor) {
-		super(userObject, primarySupplier, false);
-		this.constructor = constructor;
-	}
-
-	public boolean notify(ContextChangeEvent event) {
-		if (event.getEventType() == ContextChangeEvent.INITIAL)
-			make();
-		return false; // constructor injection is static by nature
-	}
-
-	public Object make() {
-		Object[] actualParams = processParams();
-		if (actualParams == null)
-			return null;
-		try {
-			return callConstructor(constructor, actualParams);
-		} catch (InvocationTargetException e) {
-			String msg = "Could not invoke " + constructor.getName();
-			logError(msg, e);
-			return null;
-		} catch (InstantiationException e) {
-			String msg = "Could not instantiate " + constructor.getName();
-			logError(msg, e);
-			return null;
-		}
-	}
-
-	private Object[] processParams() {
-		Class[] parameterTypes = constructor.getParameterTypes();
-		InjectionProperties[] properties = annotationSupport.getInjectParamsProperties(constructor,
-				primarySupplier);
-		Object[] actualParams = new Object[properties.length];
-		for (int i = 0; i < actualParams.length; i++) {
-			try {
-				ObjectDescriptor objectDescriptor = ObjectDescriptor.make(parameterTypes[i],
-						properties[i].getPropertyName());
-				actualParams[i] = getValue(objectDescriptor, properties[i], parameterTypes[i],
-						false, false);
-			} catch (IllegalArgumentException e) {
-				String msg = "Unable to find matching arguments for " + constructor.getName();
-				logError(msg, e);
-				return null;
-			}
-		}
-		return actualParams;
-	}
-
-	private Object callConstructor(Constructor constructor, Object[] args)
-			throws InvocationTargetException, InstantiationException {
-		if (args != null) { // make sure args are assignable
-			Class[] parameterTypes = constructor.getParameterTypes();
-			if (parameterTypes.length != args.length) {
-				// internal error, log it
-				logError(constructor, new IllegalArgumentException());
-				return null;
-			}
-			for (int i = 0; i < args.length; i++) {
-				if ((args[i] != null) && !parameterTypes[i].isAssignableFrom(args[i].getClass()))
-					return null;
-			}
-		}
-
-		Object result = null;
-		boolean wasAccessible = true;
-		if (!constructor.isAccessible()) {
-			constructor.setAccessible(true);
-			wasAccessible = false;
-		}
-		try {
-			result = constructor.newInstance(args);
-		} catch (IllegalArgumentException e) {
-			// should not happen, is checked at the start of this method
-			logError(constructor, e);
-			return null;
-		} catch (IllegalAccessException e) {
-			// should not happen as we set constructor to be accessible
-			logError(constructor, e);
-			return null;
-		} finally {
-			if (!wasAccessible)
-				constructor.setAccessible(false);
-		}
-		return result;
-	}
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionField.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionField.java
deleted file mode 100644
index b7cb645..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionField.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import java.lang.reflect.Field;
-import org.eclipse.e4.core.services.context.ContextChangeEvent;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-
-/**
- * Collection of static methods that deal with reflection-based injection at a low level.
- */
-public class InjectionField extends InjectionAbstract {
-
-	private final Field field;
-
-	public InjectionField(Object userObject, IObjectProvider primarySupplier, Field field,
-			boolean batchProcess) {
-		super(userObject, primarySupplier, batchProcess);
-		this.field = field;
-		InjectionProperties fieldProps = annotationSupport.getInjectProperties(field,
-				primarySupplier);
-		optional = fieldProps.isOptional();
-	}
-
-	public boolean notify(ContextChangeEvent event) {
-		Object userObject = getObject();
-		if (userObject == null)
-			return false;
-		// set variables based on the event type
-		int eventType = event.getEventType();
-		IObjectProvider changed = event.getContext();
-
-		boolean ignoreMissing = ignoreMissing(eventType, changed);
-		boolean injectWithNulls = injectNulls(eventType, changed);
-
-		InjectionProperties properties = annotationSupport.getInjectProperties(field,
-				primarySupplier);
-		ObjectDescriptor objectDescriptor = ObjectDescriptor.make(field.getType(), properties
-				.getPropertyName());
-		Object value;
-		try {
-			value = getValue(objectDescriptor, properties, field.getType(), ignoreMissing,
-					injectWithNulls);
-		} catch (IllegalArgumentException e) {
-			String msg = "Could not set " + field.getName();
-			logError(msg, e);
-			return true; // keep trying?
-		}
-		setField(value);
-		if (eventType == ContextChangeEvent.DISPOSE && primarySupplier.equals(changed))
-			return false;
-		return true;
-	}
-
-	private boolean setField(Object value) {
-		Object userObject = getObject();
-		boolean wasAccessible = true;
-		if (!field.isAccessible()) {
-			field.setAccessible(true);
-			wasAccessible = false;
-		}
-		try {
-			field.set(userObject, value);
-		} catch (IllegalArgumentException e) {
-			logError(field, e);
-			return false;
-		} catch (IllegalAccessException e) {
-			logError(field, e);
-			return false;
-		} finally {
-			if (!wasAccessible)
-				field.setAccessible(false);
-		}
-		return true;
-	}
-
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionMethod.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionMethod.java
deleted file mode 100644
index 69ddd8d..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectionMethod.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import org.eclipse.e4.core.services.context.ContextChangeEvent;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-
-/**
- * Collection of static methods that deal with reflection-based injection at a low level.
- */
-public class InjectionMethod extends InjectionAbstract {
-
-	private final Method method;
-
-	public InjectionMethod(Object userObject, IObjectProvider primarySupplier, Method method,
-			boolean batchProcess) {
-		super(userObject, primarySupplier, batchProcess);
-		this.method = method;
-		InjectionProperties methodProps = annotationSupport.getInjectProperties(method,
-				primarySupplier);
-		optional = methodProps.isOptional();
-	}
-
-	public boolean notify(ContextChangeEvent event) {
-		Object userObject = getObject();
-		if (userObject == null)
-			return false;
-		int eventType = event.getEventType();
-		IObjectProvider changed = event.getContext();
-		boolean ignoreMissing = ignoreMissing(eventType, changed);
-		boolean injectWithNulls = injectNulls(eventType, changed);
-		try {
-			invoke(ignoreMissing, injectWithNulls);
-		} catch (InjectionException e) {
-			logError(method, e);
-			return false;
-		}
-		if (eventType == ContextChangeEvent.DISPOSE && primarySupplier.equals(changed))
-			return false;
-		return true;
-	}
-
-	public Object invoke(boolean ignoreMissing, boolean injectWithNulls) throws InjectionException {
-		Object[] actualParams = processParams(ignoreMissing, injectWithNulls);
-		if (actualParams == null) {
-			if (!optional) {
-				String msg = "Unable to find matching argument to call method \""
-						+ method.getName() + "\"";
-				throw new InjectionException(msg);
-			}
-			return null;
-		}
-		try {
-			return callMethod(actualParams);
-		} catch (InvocationTargetException e) {
-			String msg = "Unexpected error invoking method \"" + method.getName() + "\"";
-			throw new InjectionException(msg, e);
-		}
-	}
-
-	private Object[] processParams(boolean ignoreMissing, boolean injectWithNulls) {
-		Class[] parameterTypes = method.getParameterTypes();
-		InjectionProperties[] properties = annotationSupport.getInjectParamProperties(method,
-				primarySupplier);
-		Object[] actualParams = new Object[properties.length];
-		for (int i = 0; i < actualParams.length; i++) {
-			try {
-				ObjectDescriptor objectDescriptor = ObjectDescriptor.make(parameterTypes[i],
-						properties[i].getPropertyName());
-				Object actualValue = getValue(objectDescriptor, properties[i], parameterTypes[i],
-						ignoreMissing, injectWithNulls);
-				if (actualValue == NOT_A_VALUE)
-					return null;
-				actualParams[i] = actualValue;
-			} catch (IllegalArgumentException e) {
-				String msg = "Could not invoke " + method.getName();
-				logError(msg, e);
-				return null;
-			}
-		}
-		return actualParams;
-	}
-
-	private Object callMethod(Object[] args) throws InvocationTargetException {
-		Object userObject = getObject();
-		Object result = null;
-		boolean wasAccessible = true;
-		if (!method.isAccessible()) {
-			method.setAccessible(true);
-			wasAccessible = false;
-		}
-		try {
-			result = method.invoke(userObject, args);
-		} catch (IllegalArgumentException e) {
-			// should not happen, is checked during formation of the array of actual arguments
-			logError(method, e);
-			return null;
-		} catch (IllegalAccessException e) {
-			// should not happen, is checked at the start of this method
-			logError(method, e);
-			return null;
-		} finally {
-			if (!wasAccessible)
-				method.setAccessible(false);
-		}
-		return result;
-	}
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectorImpl.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectorImpl.java
index 88829a8..2ed6436 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectorImpl.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/InjectorImpl.java
@@ -10,126 +10,608 @@
  *******************************************************************************/
 package org.eclipse.e4.core.services.internal.context;
 
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.e4.core.internal.services.ServicesActivator;
+import org.eclipse.e4.core.services.IDisposable;
+import org.eclipse.e4.core.services.context.IEclipseContext;
+import org.eclipse.e4.core.services.context.spi.ContextInjectionFactory;
 import org.eclipse.e4.core.services.context.spi.IContextConstants;
-import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.core.services.injector.AbstractObjectSupplier;
+import org.eclipse.e4.core.services.injector.IBinding;
 import org.eclipse.e4.core.services.injector.IInjector;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.IRequestor;
+import org.eclipse.e4.core.services.injector.ObjectDescriptorFactory;
 import org.eclipse.e4.core.services.internal.annotations.AnnotationsSupport;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
 
 /**
  * Reflection-based dependency injector.
  */
 public class InjectorImpl implements IInjector {
 
-	final static private String DEBUG_INJECTOR = "org.eclipse.e4.core.services/debug/injector"; //$NON-NLS-1$
-	final static private boolean shouldTrace = ServicesActivator.getDefault()
-			.getBooleanDebugOption(DEBUG_INJECTOR, false);
 	final static private String JAVA_OBJECT = "java.lang.Object"; //$NON-NLS-1$
-
+	// XXX remove
 	// plug-in class that gets replaced in Java 1.5+
-	final private static AnnotationsSupport annotationSupport = new AnnotationsSupport(); // XXX
-																							// remove;
+	final private static AnnotationsSupport annotationSupport = new AnnotationsSupport();
 
-	public InjectorImpl() {
-		// placeholder
+	// TBD thread safety
+	private Map<String, AbstractObjectSupplier> extendedSuppliers = new HashMap<String, AbstractObjectSupplier>();
+
+	private Map<AbstractObjectSupplier, List<WeakReference<?>>> injectedObjects = new HashMap<AbstractObjectSupplier, List<WeakReference<?>>>();
+	private HashMap<Class<?>, Object> singletonCache = new HashMap<Class<?>, Object>();
+	private Map<Class<?>, Set<IBinding>> bindings = new HashMap<Class<?>, Set<IBinding>>();
+
+	public boolean inject(Object object, AbstractObjectSupplier objectSupplier) {
+		// Two stages: first, go and collect {requestor, descriptor[] }
+		ArrayList<Requestor> requestors = new ArrayList<Requestor>();
+		processClassHierarchy(object, false /* no static */, true /* track */, true /* normal order */,
+				requestors);
+		// Ask suppliers to fill actual values {requestor, descriptor[], actualvalues[] }
+		if (!resolveRequestorArgs(requestors, objectSupplier, false))
+			return false;
+
+		// Call requestors in order
+		for (Requestor requestor : requestors) {
+			try {
+				if (requestor.isResolved())
+					requestor.execute();
+			} catch (InvocationTargetException e) {
+				logError("Injection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			} catch (InstantiationException e) {
+				logError("Injection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			}
+		}
+		rememberInjectedObject(object, objectSupplier);
+
+		// TBD current tests assume that @PostConstruct methods will be
+		// called after injection; however, name implies that it is only
+		// called when the object is constructed. Fix this after the 1.4/1.5 merge.
+		try {
+			processPostConstruct(object, object.getClass(), objectSupplier,
+					new ArrayList<Class<?>>(5));
+		} catch (InvocationTargetException e) {
+			logError("Injection failed for the object \"" + object.toString()
+					+ "\". Unable to process post-construct methods.", e);
+			return false;
+		} catch (InstantiationException e) {
+			logError("Injection failed for the object \"" + object.toString()
+					+ "\". Unable to process post-construct methods.", e);
+			return false;
+		}
+		return true;
 	}
 
-	public boolean inject(Object userObject, IObjectProvider objectProvider) {
-		boolean result = false;
-		try {
-			result = processClassHierarchy(userObject, false /* process static */, objectProvider);
-		} catch (InvocationTargetException e) {
-			logExternalError("Exception occured while processing injecting", userObject, e);
+	private void rememberInjectedObject(Object object, AbstractObjectSupplier objectSupplier) {
+		synchronized (injectedObjects) {
+			List<WeakReference<?>> list;
+			if (!injectedObjects.containsKey(objectSupplier)) {
+				list = new ArrayList<WeakReference<?>>();
+				injectedObjects.put(objectSupplier, list);
+			} else
+				list = injectedObjects.get(objectSupplier);
+			for (WeakReference<?> ref : list) {
+				if (object == ref.get())
+					return; // we already have it
+			}
+			list.add(new WeakReference<Object>(object));
 		}
-		objectProvider.runAndTrack(new InjectionClass(userObject, objectProvider), null);
+	}
+
+	private boolean forgetInjectedObject(Object object, AbstractObjectSupplier objectSupplier) {
+		synchronized (injectedObjects) {
+			if (!injectedObjects.containsKey(objectSupplier))
+				return false;
+			List<WeakReference<?>> list = injectedObjects.get(objectSupplier);
+			for (Iterator<WeakReference<?>> i = list.iterator(); i.hasNext();) {
+				WeakReference<?> ref = i.next();
+				if (object == ref.get())
+					i.remove();
+				return true;
+			}
+			return false;
+		}
+	}
+
+	private List<WeakReference<?>> forgetSupplier(AbstractObjectSupplier objectSupplier) {
+		synchronized (injectedObjects) {
+			if (!injectedObjects.containsKey(objectSupplier))
+				return null;
+			return injectedObjects.remove(objectSupplier);
+		}
+	}
+
+	private List<WeakReference<?>> getSupplierObjects(AbstractObjectSupplier objectSupplier) {
+		synchronized (injectedObjects) {
+			if (!injectedObjects.containsKey(objectSupplier))
+				return null;
+			return injectedObjects.get(objectSupplier);
+		}
+	}
+
+	public boolean uninject(Object object, AbstractObjectSupplier objectSupplier) {
+		if (!forgetInjectedObject(object, objectSupplier))
+			return false; // not injected at this time
+		// Two stages: first, go and collect {requestor, descriptor[] }
+		ArrayList<Requestor> requestors = new ArrayList<Requestor>();
+		processClassHierarchy(object, false /* no static */, true /* track */,
+				false /* inverse order */, requestors);
+		// might still need to get resolved values from secondary suppliers
+		// Ask suppliers to fill actual values {requestor, descriptor[], actualvalues[] }
+		if (!resolveRequestorArgs(requestors, null, true /* fill with nulls */))
+			return false;
+
+		// Call requestors in order
+		for (Requestor requestor : requestors) {
+			try {
+				requestor.execute();
+			} catch (InvocationTargetException e) {
+				logError("Uninjection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			} catch (InstantiationException e) {
+				logError("Uninjection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public Object invoke(Object object, String methodName, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, CoreException {
+		Object result = invokeUsingClass(object, object.getClass(), methodName,
+				IInjector.NOT_A_VALUE, objectSupplier);
+		if (result == IInjector.NOT_A_VALUE) {
+			IStatus status = new Status(IStatus.ERROR, "org.eclipse.e4.core.services",
+					"Unable to find matching method to invoke");
+			throw new CoreException(status);
+		}
 		return result;
 	}
 
-	// TBD use null object to inject statics
-	public boolean injectStatic(Class clazz, IObjectProvider objectProvider) {
+	public Object invoke(Object object, String methodName, Object defaultValue,
+			AbstractObjectSupplier objectSupplier) throws InvocationTargetException {
+		return invokeUsingClass(object, object.getClass(), methodName, defaultValue, objectSupplier);
+	}
+
+	private Object invokeUsingClass(Object userObject, Class<?> currentClass, String methodName,
+			Object defaultValue, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException {
+		Method[] methods = currentClass.getDeclaredMethods();
+		for (int j = 0; j < methods.length; j++) {
+			Method method = methods[j];
+			if (!method.getName().equals(methodName))
+				continue;
+			MethodRequestor requestor = new MethodRequestor(method, userObject, false, false, true);
+
+			Object[] actualArgs = resolveArgs(requestor, objectSupplier, false);
+			int unresolved = unresolved(actualArgs);
+			if (unresolved != -1) {
+				logError("Injection failed for object \""
+						+ requestor.getRequestingObject().toString()
+						+ "\". Unable to find value for \""
+						+ requestor.getDependentObjects()[unresolved] + "\"");
+				return null;
+			}
+			requestor.setResolvedArgs(actualArgs);
+
+			try {
+				return requestor.execute();
+			} catch (InstantiationException e) {
+				// TBD clean up the error handling; need to propagate original exception
+				logError("Exception occured in the injected method " + method.getName(), e);
+				return null;
+			}
+		}
+		Class<?> superClass = currentClass.getSuperclass();
+		if (superClass == null) {
+			return defaultValue;
+		}
+		return invokeUsingClass(userObject, superClass, methodName, defaultValue, objectSupplier);
+	}
+
+	public Object make(Class<?> clazz, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, InstantiationException {
+		IObjectDescriptor descriptor = ObjectDescriptorFactory.make(clazz, false);
+		return make(descriptor, objectSupplier);
+	}
+
+	public Object make(IObjectDescriptor descriptor, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, InstantiationException {
+		IBinding binding = findBinding(descriptor);
+		if (binding == null) {
+			Class<?> desiredClass = descriptor.getElementClass();
+			return internalMake(desiredClass, objectSupplier);
+		}
+		return internalMake(binding.getImplementationClass(), objectSupplier);
+	}
+
+	private Object internalMake(Class<?> clazz, AbstractObjectSupplier objectSupplier)
+			throws InvocationTargetException, InstantiationException {
+
+		boolean isSingleton = clazz.isAnnotationPresent(Singleton.class);
+		if (isSingleton) {
+			synchronized (singletonCache) {
+				if (singletonCache.containsKey(clazz))
+					return singletonCache.get(clazz);
+			}
+		}
+
+		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
+		// Sort the constructors by descending number of constructor arguments
+		ArrayList<Constructor<?>> sortedConstructors = new ArrayList<Constructor<?>>(
+				constructors.length);
+		for (Constructor<?> constructor : constructors)
+			sortedConstructors.add(constructor);
+		Collections.sort(sortedConstructors, new Comparator<Constructor<?>>() {
+			public int compare(Constructor<?> c1, Constructor<?> c2) {
+				int l1 = c1.getParameterTypes().length;
+				int l2 = c2.getParameterTypes().length;
+				return l2 - l1;
+			}
+		});
+
+		for (Constructor<?> constructor : sortedConstructors) {
+			// skip private and protected constructors; allow public and package visibility
+			int modifiers = constructor.getModifiers();
+			if (((modifiers & Modifier.PRIVATE) != 0) || ((modifiers & Modifier.PROTECTED) != 0))
+				continue;
+
+			// unless this is the default constructor, it has to be tagged
+			InjectionProperties cProps = annotationSupport.getInjectProperties(constructor);
+			if (!cProps.shouldInject() && constructor.getParameterTypes().length != 0)
+				continue;
+
+			ConstructorRequestor requestor = new ConstructorRequestor(constructor);
+			Object[] actualArgs = resolveArgs(requestor, objectSupplier, false);
+			if (unresolved(actualArgs) != -1)
+				continue;
+			requestor.setResolvedArgs(actualArgs);
+
+			Object newInstance = requestor.execute();
+			if (newInstance != null) {
+				inject(newInstance, objectSupplier);
+				if (isSingleton) {
+					synchronized (singletonCache) { // TBD this is not quite right, synch the method
+						singletonCache.put(clazz, newInstance);
+					}
+				}
+				return newInstance;
+			}
+		}
+
+		logError("Could not find satisfiable constructor in class " + clazz.getName());
+		return null;
+	}
+
+	public boolean injectStatic(Class<?> clazz, AbstractObjectSupplier objectSupplier) {
+		// TBD add processing on a null object
+		Object object;
 		try {
-			Object object = make(clazz, objectProvider);
-			return processClassHierarchy(object, true /* process static */, objectProvider);
+			object = make(clazz, objectSupplier);
 		} catch (InvocationTargetException e) {
 			// try-catch won't be necessary once we stop creating an object
 			e.printStackTrace();
+			return false;
 		} catch (InstantiationException e) {
 			// try-catch won't be necessary once we stop creating an object
 			e.printStackTrace();
+			return false;
 		}
-		return false;
+
+		// TBD this is copy/paste from as invoke() with static = true.
+		// Two stages: first, go and collect {requestor, descriptor[] }
+		ArrayList<Requestor> requestors = new ArrayList<Requestor>();
+		processClassHierarchy(object, true /* static */, true /* track */, true /* normal order */,
+				requestors);
+		// Ask suppliers to fill actual values {requestor, descriptor[], actualvalues[] }
+		if (!resolveRequestorArgs(requestors, objectSupplier, false))
+			return false;
+
+		// Call requestors in order
+		for (Requestor requestor : requestors) {
+			try {
+				requestor.execute();
+			} catch (InvocationTargetException e) {
+				logError("Injection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			} catch (InstantiationException e) {
+				logError("Injection failed for the object \"" + object.toString()
+						+ "\". Unable to execute \"" + requestor.toString() + "\"");
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	public boolean update(IRequestor[] requestors, AbstractObjectSupplier objectSupplier) {
+		ArrayList<Requestor> list = new ArrayList<Requestor>(requestors.length);
+		for (IRequestor requestor : requestors) {
+			list.add((Requestor) requestor);
+		}
+		resolveRequestorArgs(list, objectSupplier, true);
+
+		// Call requestors in order
+		for (IRequestor requestor : requestors) {
+			try {
+				((Requestor) requestor).execute();
+			} catch (InvocationTargetException e) {
+				logError("Injection failed for the object \""
+						+ requestor.getRequestingObject().toString() + "\". Unable to execute \""
+						+ requestor.toString() + "\"");
+				return false;
+			} catch (InstantiationException e) {
+				logError("Injection failed for the object \""
+						+ requestor.getRequestingObject().toString() + "\". Unable to execute \""
+						+ requestor.toString() + "\"");
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public boolean disposed(AbstractObjectSupplier objectSupplier) {
+		List<WeakReference<?>> references = getSupplierObjects(objectSupplier);
+		if (references == null)
+			return true;
+		Object[] objects = new Object[references.size()];
+		int count = 0;
+		for (WeakReference<?> ref : references) {
+			Object object = ref.get();
+			if (object != null) {
+				objects[count] = object;
+				count++;
+			}
+		}
+		for (int i = 0; i < count; i++) {
+			processPreDestory(objects[i], objects[i].getClass(), new ArrayList<Class<?>>(5));
+			uninject(objects[i], objectSupplier);
+		}
+		forgetSupplier(objectSupplier);
+		return true;
+	}
+
+	private void processPreDestory(Object userObject, Class<?> objectClass,
+			ArrayList<Class<?>> classHierarchy) {
+		Class<?> superClass = objectClass.getSuperclass();
+		if (superClass != null && !superClass.getName().equals(JAVA_OBJECT)) {
+			classHierarchy.add(objectClass);
+			processPreDestory(userObject, superClass, classHierarchy);
+			classHierarchy.remove(objectClass);
+		}
+		Method[] methods = objectClass.getDeclaredMethods();
+		for (int i = 0; i < methods.length; i++) {
+			Method method = methods[i];
+			if (method.getParameterTypes().length > 0) // TBD why?
+				continue;
+			if (!annotationSupport.isPreDestory(method))
+				continue;
+			if (!isOverridden(method, classHierarchy)) {
+				// TBD optional @PreDestory? might make sense if we allow args on those methods
+				MethodRequestor requestor = new MethodRequestor(method, userObject, false, false,
+						false);
+				try {
+					requestor.execute();
+				} catch (InvocationTargetException e) {
+					logError("Unable to call pre-destory method \"" + method.getName() + "\"", e);
+				} catch (InstantiationException e) {
+					logError("Unable to call pre-destory method \"" + method.getName() + "\"", e);
+				}
+			}
+		}
+		if (userObject instanceof IDisposable)
+			((IDisposable) userObject).dispose();
+	}
+
+	private boolean resolveRequestorArgs(ArrayList<Requestor> requestors,
+			AbstractObjectSupplier objectSupplier, boolean fillNulls) {
+		for (Requestor requestor : requestors) {
+			Object[] actualArgs = resolveArgs(requestor, objectSupplier, fillNulls);
+			int unresolved = unresolved(actualArgs);
+			if (unresolved == -1) {
+				requestor.setResolvedArgs(actualArgs);
+				continue;
+			}
+
+			if (requestor.isOptional())
+				requestor.setResolvedArgs(null);
+			else {
+				logError("Injection failed for object \""
+						+ requestor.getRequestingObject().toString()
+						+ "\". Unable to find value for \""
+						+ requestor.getDependentObjects()[unresolved] + "\"");
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private Object[] resolveArgs(Requestor requestor, AbstractObjectSupplier objectSupplier,
+			boolean fillNulls) {
+		IObjectDescriptor[] descriptors = requestor.getDependentObjects();
+
+		// 0) initial fill - all are unresolved
+		Object[] actualArgs = new Object[descriptors.length];
+		for (int i = 0; i < actualArgs.length; i++) {
+			actualArgs[i] = NOT_A_VALUE;
+		}
+
+		// 1) check if we have a Provider<T>
+		for (int i = 0; i < actualArgs.length; i++) {
+			Class<?> providerClass = getProviderType(descriptors[i].getElementType());
+			if (providerClass == null)
+				continue;
+			actualArgs[i] = new ProviderImpl<Class<?>>(descriptors[i], this, objectSupplier);
+			descriptors[i] = null; // mark as used
+		}
+
+		// 2) use the primary supplier
+		if (objectSupplier != null) {
+			Object[] primarySupplierArgs = objectSupplier.get(descriptors, requestor);
+			for (int i = 0; i < actualArgs.length; i++) {
+				if (descriptors[i] == null)
+					continue; // already resolved
+				if (primarySupplierArgs[i] != NOT_A_VALUE) {
+					actualArgs[i] = primarySupplierArgs[i];
+					descriptors[i] = null; // mark as used
+				}
+			}
+		}
+
+		// 3) try extended suppliers
+		for (int i = 0; i < actualArgs.length; i++) {
+			if (descriptors[i] == null)
+				continue; // already resolved
+			AbstractObjectSupplier extendedSupplier = findExtendedSupplier(descriptors[i]);
+			if (extendedSupplier == null)
+				continue;
+			Object result = extendedSupplier.get(descriptors[i], requestor);
+			if (result != NOT_A_VALUE) {
+				actualArgs[i] = result;
+				descriptors[i] = null; // mark as used
+			}
+		}
+
+		// 4) try the bindings
+		for (int i = 0; i < actualArgs.length; i++) {
+			if (descriptors[i] == null)
+				continue; // already resolved
+			IBinding binding = findBinding(descriptors[i]);
+			if (binding != null) {
+				try {
+					actualArgs[i] = internalMake(binding.getImplementationClass(), objectSupplier);
+				} catch (InvocationTargetException e) {
+					logError("Unable to create object for class \""
+							+ binding.getImplementationClass() + "\".", e);
+					continue;
+				} catch (InstantiationException e) {
+					logError("Unable to create object for class \""
+							+ binding.getImplementationClass() + "\".", e);
+					continue;
+				}
+			}
+		}
+
+		// 5) post process
+		descriptors = requestor.getDependentObjects(); // reset nulled out values
+		for (int i = 0; i < descriptors.length; i++) {
+			// check that values are of a correct type
+			if (actualArgs[i] != null && actualArgs[i] != IInjector.NOT_A_VALUE) {
+				Class<?> descriptorsClass = descriptors[i].getElementClass();
+				if (!descriptorsClass.isAssignableFrom(actualArgs[i].getClass()))
+					actualArgs[i] = IInjector.NOT_A_VALUE;
+			}
+			// replace optional unresolved values with null
+			if (descriptors[i].isOptional() && actualArgs[i] == IInjector.NOT_A_VALUE)
+				actualArgs[i] = null;
+			else if (fillNulls && actualArgs[i] == IInjector.NOT_A_VALUE)
+				actualArgs[i] = null;
+		}
+
+		return actualArgs;
+	}
+
+	private AbstractObjectSupplier findExtendedSupplier(IObjectDescriptor descriptor) {
+		String[] qualifiers = descriptor.getQualifiers();
+		if (qualifiers == null)
+			return null;
+		for (String qualifier : qualifiers) {
+			if (extendedSuppliers.containsKey(qualifier))
+				return extendedSuppliers.get(qualifier);
+		}
+		return null;
+	}
+
+	private int unresolved(Object[] actualArgs) {
+		for (int i = 0; i < actualArgs.length; i++) {
+			if (actualArgs[i] == IInjector.NOT_A_VALUE)
+				return i;
+		}
+		return -1;
+	}
+
+	private void processClassHierarchy(Object userObject, boolean processStatic, boolean track,
+			boolean normalOrder, List<Requestor> requestors) {
+		processClass(userObject, (userObject == null) ? null : userObject.getClass(),
+				new ArrayList<Class<?>>(5), processStatic, track, normalOrder, requestors);
 	}
 
 	/**
 	 * Make the processor visit all declared members on the given class and all superclasses
-	 * 
-	 * @throws InvocationTargetException
 	 */
-	private boolean processClass(Object userObject, Class objectsClass, ArrayList classHierarchy,
-			boolean processStatic, IObjectProvider objectProvider) throws InvocationTargetException {
+	private void processClass(Object userObject, Class<?> objectsClass,
+			ArrayList<Class<?>> classHierarchy, boolean processStatic, boolean track,
+			boolean normalOrder, List<Requestor> requestors) {
 		// order: superclass, fields, methods
 		if (objectsClass != null) {
-			Class superClass = objectsClass.getSuperclass();
+			Class<?> superClass = objectsClass.getSuperclass();
 			if (!superClass.getName().equals(JAVA_OBJECT)) {
 				classHierarchy.add(objectsClass);
-				if (!processClass(userObject, superClass, classHierarchy, processStatic,
-						objectProvider))
-					return false;
+				processClass(userObject, superClass, classHierarchy, processStatic, track,
+						normalOrder, requestors);
 				classHierarchy.remove(objectsClass);
 			}
 		}
-		if (!processFields(userObject, objectsClass, processStatic, objectProvider))
-			return false;
-		if (!processMethods(userObject, objectsClass, classHierarchy, processStatic, objectProvider))
-			return false;
-		return true;
-	}
-
-	private boolean processClassHierarchy(Object userObject, boolean processStatic,
-			IObjectProvider objectProvider) throws InvocationTargetException {
-		if (!processClass(userObject, (userObject == null) ? null : userObject.getClass(),
-				new ArrayList(5), processStatic, objectProvider))
-			return false;
-		return true;
+		if (normalOrder) {
+			processFields(userObject, objectsClass, processStatic, track, requestors);
+			processMethods(userObject, objectsClass, classHierarchy, processStatic, track,
+					requestors);
+		} else {
+			processMethods(userObject, objectsClass, classHierarchy, processStatic, track,
+					requestors);
+			processFields(userObject, objectsClass, processStatic, track, requestors);
+		}
 	}
 
 	/**
 	 * Make the processor visit all declared fields on the given class.
 	 */
-	private boolean processFields(Object userObject, Class objectsClass, boolean processStatic,
-			IObjectProvider objectProvider) {
+	private void processFields(Object userObject, Class<?> objectsClass, boolean processStatic,
+			boolean track, List<Requestor> requestors) {
 		Field[] fields = objectsClass.getDeclaredFields();
 		for (int i = 0; i < fields.length; i++) {
 			Field field = fields[i];
 			if (Modifier.isStatic(field.getModifiers()) != processStatic)
 				continue;
-			InjectionProperties properties = annotationSupport.getInjectProperties(field,
-					objectProvider);
+
+			// XXX limit to "should inject"
+			InjectionProperties properties = annotationSupport.getInjectProperties(field);
+			// XXX this will be removed on 1.4/1.5 merge
 			if (field.getName().startsWith(IContextConstants.INJECTION_PREFIX))
 				properties.setInject(true);
-
 			if (!properties.shouldInject())
 				continue;
-			objectProvider.runAndTrack(new InjectionField(userObject, objectProvider, field,
-					properties.groupUpdates()), null);
+
+			requestors.add(new FieldRequestor(field, userObject, track, properties.groupUpdates(),
+					properties.isOptional()));
 		}
-		return true;
 	}
 
 	/**
@@ -137,9 +619,9 @@
 	 * 
 	 * @throws InvocationTargetException
 	 */
-	private boolean processMethods(final Object userObject, Class objectsClass,
-			ArrayList classHierarchy, boolean processStatic, IObjectProvider objectProvider)
-			throws InvocationTargetException {
+	private void processMethods(final Object userObject, Class<?> objectsClass,
+			ArrayList<Class<?>> classHierarchy, boolean processStatic, boolean track,
+			List<Requestor> requestors) {
 		Method[] methods = objectsClass.getDeclaredMethods();
 		for (int i = 0; i < methods.length; i++) {
 			final Method method = methods[i];
@@ -147,50 +629,49 @@
 				continue; // process in the subclass
 			if (Modifier.isStatic(method.getModifiers()) != processStatic)
 				continue;
-			InjectionProperties properties = annotationSupport.getInjectProperties(method,
-					objectProvider);
+
+			InjectionProperties properties = annotationSupport.getInjectProperties(method);
 			if (method.getName().startsWith(IContextConstants.INJECTION_PREFIX))
 				properties.setInject(true);
 
-			if (properties.getHandlesEvent() != null) {
-				// XXX this is wrong, but it will be removed anyway
-				ObjectDescriptor desc = ObjectDescriptor.make(IEventBroker.class);
-				IEventBroker eventBroker = (IEventBroker) objectProvider.get(desc);
-				eventBroker.subscribe(properties.getHandlesEvent(), null, new EventHandler() {
-					public void handleEvent(Event event) {
-						Object data = event.getProperty(IEventBroker.DATA);
-						boolean wasAccessible = method.isAccessible();
-						if (!wasAccessible) {
-							method.setAccessible(true);
-						}
-						try {
-							method.invoke(userObject, data);
-						} catch (Exception e) {
-							throw new RuntimeException(e);
-						} finally {
-							if (!wasAccessible) {
-								method.setAccessible(false);
-							}
-						}
-					}
-				}, properties.getEventHeadless());
-				continue;
-			}
+			// replace with @Event("name") qualifier
+			// if (properties.getHandlesEvent() != null) {
+			// // XXX this is wrong, but it will be removed anyway
+			// ObjectDescriptor desc = ObjectDescriptor.make(IEventBroker.class);
+			// IEventBroker eventBroker = (IEventBroker) objectProvider.get(desc);
+			// eventBroker.subscribe(properties.getHandlesEvent(), null, new EventHandler() {
+			// public void handleEvent(Event event) {
+			// Object data = event.getProperty(IEventBroker.DATA);
+			// boolean wasAccessible = method.isAccessible();
+			// if (!wasAccessible) {
+			// method.setAccessible(true);
+			// }
+			// try {
+			// method.invoke(userObject, data);
+			// } catch (Exception e) {
+			// throw new RuntimeException(e);
+			// } finally {
+			// if (!wasAccessible) {
+			// method.setAccessible(false);
+			// }
+			// }
+			// }
+			// }, properties.getEventHeadless());
+			// continue;
+			// }
 
 			if (!properties.shouldInject())
 				continue;
 
-			objectProvider.runAndTrack(new InjectionMethod(userObject, objectProvider, method,
-					properties.groupUpdates()), null);
+			requestors.add(new MethodRequestor(method, userObject, track,
+					properties.groupUpdates(), properties.isOptional()));
 		}
-		return true;
 	}
 
-	// TBD this is the same method as in the class injector
 	/**
 	 * Checks if a given method is overridden with an injectable method.
 	 */
-	private boolean isOverridden(Method method, ArrayList classHierarchy) {
+	private boolean isOverridden(Method method, ArrayList<Class<?>> classHierarchy) {
 		int modifiers = method.getModifiers();
 		if (Modifier.isPrivate(modifiers))
 			return false;
@@ -199,141 +680,175 @@
 		// method is not private if we reached this line, check not(public OR protected)
 		boolean isDefault = !(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers));
 
-		for (Iterator i = classHierarchy.iterator(); i.hasNext();) {
-			Class subClass = (Class) i.next();
-			Method override = null;
+		for (Class<?> subClass : classHierarchy) {
 			try {
-				override = subClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
+				subClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
 			} catch (SecurityException e) {
 				continue;
 			} catch (NoSuchMethodException e) {
 				continue; // this is the desired outcome
 			}
-			if (override != null) {
-				if (isDefault) { // must be in the same package to override
-					Package originalPackage = method.getDeclaringClass().getPackage();
-					Package overridePackage = subClass.getPackage();
+			if (isDefault) { // must be in the same package to override
+				Package originalPackage = method.getDeclaringClass().getPackage();
+				Package overridePackage = subClass.getPackage();
 
-					if (originalPackage == null && overridePackage == null)
-						return true;
-					if (originalPackage == null || overridePackage == null)
-						return false;
-					if (originalPackage.equals(overridePackage))
-						return true;
-				} else
+				if (originalPackage == null && overridePackage == null)
 					return true;
-			}
+				if (originalPackage == null || overridePackage == null)
+					return false;
+				if (originalPackage.equals(overridePackage))
+					return true;
+			} else
+				return true;
 		}
 		return false;
 	}
 
-	public Object invoke(Object userObject, String methodName, IObjectProvider objectProvider)
-			throws InvocationTargetException, CoreException {
-		Method[] methods = userObject.getClass().getDeclaredMethods();
-		for (int j = 0; j < methods.length; j++) {
-			Method method = methods[j];
-			if (!method.getName().equals(methodName))
-				continue;
-
-			InjectionMethod injectMethod = new InjectionMethod(userObject, objectProvider, method,
-					false);
-			try {
-				return injectMethod.invoke(false, false);
-			} catch (InjectionException e) {
-				IStatus status = new Status(IStatus.ERROR, "org.eclipse.e4.core.services",
-						"Unable to invoke method");
-				throw new CoreException(status);
-			}
-		}
-		IStatus status = new Status(IStatus.ERROR, "org.eclipse.e4.core.services",
-				"Unable to find matching method to invoke");
-		throw new CoreException(status);
-	}
-
-	public Object invoke(Object userObject, String methodName, Object defaultValue,
-			IObjectProvider objectProvider) throws InvocationTargetException {
-		return invokeUsingClass(userObject, userObject.getClass(), methodName, defaultValue,
-				objectProvider);
-	}
-
-	public Object invokeUsingClass(Object userObject, Class currentClass, String methodName,
-			Object defaultValue, IObjectProvider objectProvider) throws InvocationTargetException {
-		Method[] methods = currentClass.getDeclaredMethods();
-		for (int j = 0; j < methods.length; j++) {
-			Method method = methods[j];
-			if (!method.getName().equals(methodName))
-				continue;
-
-			InjectionMethod injectMethod = new InjectionMethod(userObject, objectProvider, method,
-					false);
-			try {
-				return injectMethod.invoke(false, false);
-			} catch (InjectionException e) {
-				// TBD? abort or continue?
-				logExternalError("Exception occured in the injectd method " + method.getName(),
-						userObject, e);
-			}
-		}
-		Class superClass = currentClass.getSuperclass();
-		if (superClass == null) {
-			return defaultValue;
-		}
-		return invokeUsingClass(userObject, superClass, methodName, defaultValue, objectProvider);
-	}
-
-	public Object make(Class clazz, IObjectProvider objectProvider)
+	private void processPostConstruct(Object userObject, Class<?> objectClass,
+			AbstractObjectSupplier objectSupplier, ArrayList<Class<?>> classHierarchy)
 			throws InvocationTargetException, InstantiationException {
-		Constructor[] constructors = clazz.getDeclaredConstructors();
+		Class<?> superClass = objectClass.getSuperclass();
+		if (superClass != null && !superClass.getName().equals(JAVA_OBJECT)) {
+			classHierarchy.add(objectClass);
+			processPostConstruct(userObject, superClass, objectSupplier, classHierarchy);
+			classHierarchy.remove(objectClass);
+		}
+		Method[] methods = objectClass.getDeclaredMethods();
+		for (int i = 0; i < methods.length; i++) {
+			Method method = methods[i];
+			if (!isPostConstruct(method))
+				continue;
+			if (isOverridden(method, classHierarchy))
+				continue;
 
-		// Sort the constructors by descending number of constructor arguments
-		ArrayList sortedConstructors = new ArrayList(constructors.length);
-		for (int i = 0; i < constructors.length; i++)
-			sortedConstructors.add(constructors[i]);
-		Collections.sort(sortedConstructors, new Comparator() {
-			public int compare(Object c1, Object c2) {
-				int l1 = ((Constructor) c1).getParameterTypes().length;
-				int l2 = ((Constructor) c2).getParameterTypes().length;
-				return l2 - l1;
+			MethodRequestor requestor = new MethodRequestor(method, userObject, false, false, false);
+			Object[] actualArgs = resolveArgs(requestor, objectSupplier, false);
+			int unresolved = unresolved(actualArgs);
+			if (unresolved != -1) {
+				logError("Injection failed for object \""
+						+ requestor.getRequestingObject().toString()
+						+ "\". Unable to find value for \""
+						+ requestor.getDependentObjects()[unresolved] + "\"");
+				continue;
 			}
-		});
+			requestor.setResolvedArgs(actualArgs);
 
-		for (Iterator i = sortedConstructors.iterator(); i.hasNext();) {
-			Constructor constructor = (Constructor) i.next();
-
-			// skip private and protected constructors; allow public and package visibility
-			if (((constructor.getModifiers() & Modifier.PRIVATE) != 0)
-					|| ((constructor.getModifiers() & Modifier.PROTECTED) != 0))
-				continue;
-
-			// unless this is the default constructor, it has to be tagged
-			InjectionProperties cProps = annotationSupport.getInjectProperties(constructor,
-					objectProvider);
-			if (!cProps.shouldInject() && constructor.getParameterTypes().length != 0)
-				continue;
-
-			InjectionConstructor injectedConstructor = new InjectionConstructor(null,
-					objectProvider, constructor);
-			Object newInstance = injectedConstructor.make();
-			if (newInstance != null) {
-				inject(newInstance, objectProvider);
-				return newInstance;
+			try {
+				requestor.execute();
+			} catch (InvocationTargetException e) {
+				logError("Unable to call post-construct method \"" + method.getName() + "\"", e);
+			} catch (InstantiationException e) {
+				logError("Unable to call post-construct method \"" + method.getName() + "\"", e);
 			}
 		}
+	}
 
-		if (shouldTrace)
-			System.out
-					.println("Could not find satisfiable constructor in class " + clazz.getName());
+	// TBD simplify this: only one non-annotation and one "implements IInitializable"?
+	/**
+	 * Returns whether the given method is a post-construction process method, as defined by the
+	 * class comment of {@link ContextInjectionFactory}.
+	 */
+	private boolean isPostConstruct(Method method) {
+		boolean isPostConstruct = annotationSupport.isPostConstruct(method);
+		if (isPostConstruct)
+			return true;
+		if (!method.getName().equals(IContextConstants.INJECTION_SET_CONTEXT_METHOD))
+			return false;
+		Class<?>[] parms = method.getParameterTypes();
+		if (parms.length == 0)
+			return true;
+		if (parms.length == 1 && parms[0].equals(IEclipseContext.class))
+			return true;
+		return false;
+	}
+
+	/**
+	 * Returns null if not a provider
+	 */
+	private Class<?> getProviderType(Type type) {
+		if (!(type instanceof ParameterizedType))
+			return null;
+		Type rawType = ((ParameterizedType) type).getRawType();
+		if (!(rawType instanceof Class<?>))
+			return null;
+		boolean isProvider = ((Class<?>) rawType).equals(Provider.class);
+		if (!isProvider)
+			return null;
+		Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
+		if (actualTypes.length != 1)
+			return null;
+		if (!(actualTypes[0] instanceof Class<?>))
+			return null;
+		return (Class<?>) actualTypes[0];
+	}
+
+	public IBinding addBinding(Class<?> clazz) {
+		return addBinding(new Binding(clazz, this));
+	}
+
+	public IBinding addBinding(IBinding binding) {
+		Class<?> clazz = binding.getDescribedClass();
+		synchronized (bindings) {
+			if (bindings.containsKey(clazz)) {
+				Set<IBinding> collection = bindings.get(clazz);
+				String desiredQualifierName = binding.getQualifierName();
+				for (Iterator<IBinding> i = collection.iterator(); i.hasNext();) {
+					IBinding collectionBinding = i.next();
+					if (eq(collectionBinding.getQualifierName(), desiredQualifierName)) {
+						i.remove();
+						break;
+					}
+				}
+				collection.add(binding);
+			} else {
+				Set<IBinding> collection = new HashSet<IBinding>(1);
+				collection.add(binding);
+				bindings.put(clazz, collection);
+			}
+		}
+		return binding;
+	}
+
+	private IBinding findBinding(IObjectDescriptor descriptor) {
+		Class<?> desiredClass = getProviderType(descriptor.getElementType());
+		if (desiredClass == null)
+			desiredClass = descriptor.getElementClass();
+		synchronized (bindings) {
+			if (!bindings.containsKey(desiredClass))
+				return null;
+			Set<IBinding> collection = bindings.get(desiredClass);
+			String desiredQualifierName = descriptor.getQualifierValue(Named.class.getName());
+
+			for (Iterator<IBinding> i = collection.iterator(); i.hasNext();) {
+				IBinding collectionBinding = i.next();
+				if (eq(collectionBinding.getQualifierName(), desiredQualifierName))
+					return collectionBinding;
+			}
+		}
 		return null;
 	}
 
-	private void logExternalError(String msg, Object destination, Exception e) {
-		System.out.println(msg + " " + destination.toString()); //$NON-NLS-1$
+	/**
+	 * Are two, possibly null, string equal?
+	 */
+	private boolean eq(String str1, String str2) {
+		if (str1 == null && str2 == null)
+			return true;
+		if (str1 == null || str2 == null)
+			return false;
+		return str1.equals(str2);
+	}
+
+	// TBD implement logging
+	private void logError(String msg) {
+		logError(msg, new InjectionException());
+	}
+
+	private void logError(String msg, Throwable e) {
+		if (msg != null)
+			System.err.println(msg);
 		if (e != null)
 			e.printStackTrace();
-		// TBD convert this into real logging
-		// String msg = NLS.bind("Injection failed", destination.toString());
-		// RuntimeLog.log(new Status(IStatus.WARNING,
-		// IRuntimeConstants.PI_COMMON, 0, msg, e));
 	}
 
 }
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/MethodRequestor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/MethodRequestor.java
new file mode 100644
index 0000000..574dcad
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/MethodRequestor.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.ObjectDescriptorFactory;
+
+public class MethodRequestor extends Requestor {
+
+	final private Method method;
+
+	public MethodRequestor(Method method, Object requestingObject, boolean track,
+			boolean groupUpdates, boolean optional) {
+		super(requestingObject, track, groupUpdates, optional);
+		this.method = method;
+	}
+
+	public Object execute() throws InvocationTargetException, InstantiationException {
+		return callMethod(method, actualArgs);
+	}
+
+	@Override
+	public IObjectDescriptor[] getDependentObjects() {
+		Type[] parameterTypes = method.getGenericParameterTypes();
+		// TBD make getInjectParamProperties produce ObjectDescriptors
+		InjectionProperties[] properties = annotationSupport.getInjectParamProperties(method);
+		IObjectDescriptor[] descriptors = new IObjectDescriptor[properties.length];
+		for (int i = 0; i < properties.length; i++) {
+			descriptors[i] = ObjectDescriptorFactory.make(parameterTypes[i], properties[i]
+					.getPropertyName(), properties[i].isOptional());
+		}
+		return descriptors;
+	}
+
+	private Object callMethod(Method method, Object[] args) throws InvocationTargetException {
+		Object userObject = getRequestingObject();
+		if (userObject == null)
+			return null;
+		Object result = null;
+		boolean wasAccessible = true;
+		if (!method.isAccessible()) {
+			method.setAccessible(true);
+			wasAccessible = false;
+		}
+		try {
+			result = method.invoke(userObject, args);
+		} catch (IllegalArgumentException e) {
+			// should not happen, is checked during formation of the array of actual arguments
+			logError(method, e);
+			return null;
+		} catch (IllegalAccessException e) {
+			// should not happen, is checked at the start of this method
+			logError(method, e);
+			return null;
+		} finally {
+			if (!wasAccessible)
+				method.setAccessible(false);
+		}
+		return result;
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectDescriptor.java
similarity index 62%
rename from bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptor.java
rename to bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectDescriptor.java
index ae2be2b..4041a55 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/injector/ObjectDescriptor.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectDescriptor.java
@@ -8,45 +8,50 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.e4.core.services.injector;
+package org.eclipse.e4.core.services.internal.context;
 
-import javax.inject.Named;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
 
 /**
  * NOTE: This is a preliminary form; this API will change.
  * 
  * @noextend This class is not intended to be subclassed by clients.
  */
-public class ObjectDescriptor {
+public class ObjectDescriptor implements IObjectDescriptor {
 
-	final private Class desiredClass;
+	final private Type desiredType;
 	final private String[] qualifiers;
 	final private String[] values;
 
-	static final private String named = Named.class.getName();
+	// TBD make "Optional" a qualifier?
+	final private boolean optional;
 
-	static public ObjectDescriptor make(Class clazz) {
-		return new ObjectDescriptor(clazz, null, null);
-	}
-
-	static public ObjectDescriptor make(String name) {
-		return new ObjectDescriptor(null, new String[] { named }, new String[] { name });
-	}
-
-	static public ObjectDescriptor make(Class clazz, String name) {
-		if (name == null)
-			return make(clazz);
-		return new ObjectDescriptor(clazz, new String[] { named }, new String[] { name });
-	}
-
-	public ObjectDescriptor(Class desiredClass, String[] qualifiers, String[] values) {
-		this.desiredClass = desiredClass;
+	public ObjectDescriptor(Type desiredType, String[] qualifiers, String[] values, boolean optional) {
+		this.desiredType = desiredType;
 		this.qualifiers = qualifiers;
 		this.values = values;
+		this.optional = optional;
 	}
 
-	public Class getElementClass() {
-		return desiredClass;
+	// TBD rename getDesiredClass()
+	public Class<?> getElementClass() {
+		if (desiredType instanceof Class<?>)
+			return (Class<?>) desiredType;
+		if (desiredType instanceof ParameterizedType)
+			return (Class<?>) ((ParameterizedType) desiredType).getRawType(); // XXX this is wrong;
+																				// might be
+																				// Param<T<T2>>
+		return null;
+	}
+
+	public Type getElementType() {
+		return desiredType;
+	}
+
+	public boolean isOptional() {
+		return optional;
 	}
 
 	public boolean hasQualifier(String qualifier) {
@@ -61,6 +66,10 @@
 		return false;
 	}
 
+	public String[] getQualifiers() {
+		return qualifiers;
+	}
+
 	/**
 	 * Returns null if qualifier is not present
 	 * 
@@ -81,8 +90,8 @@
 
 	public String toString() {
 		StringBuffer buffer = new StringBuffer();
-		if (desiredClass != null)
-			buffer.append(desiredClass.getName());
+		if (desiredType != null)
+			buffer.append(((Class<?>) desiredType).getName());
 		else
 			buffer.append("_descriptor_");
 		if (qualifiers != null) {
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectProviderContext.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectProviderContext.java
deleted file mode 100644
index f8cf2cb..0000000
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ObjectProviderContext.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*******************************************************************************
- * 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.core.services.internal.context;
-
-import javax.inject.Named;
-import org.eclipse.e4.core.services.context.IEclipseContext;
-import org.eclipse.e4.core.services.context.IRunAndTrack;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.injector.ObjectDescriptor;
-
-public class ObjectProviderContext implements IObjectProvider {
-
-	final static private String ECLIPSE_CONTEXT_NAME = IEclipseContext.class.getName();
-
-	final private IEclipseContext context;
-
-	public ObjectProviderContext(IEclipseContext context) {
-		this.context = context;
-	}
-
-	public boolean containsKey(ObjectDescriptor properties) {
-		String key = getKey(properties);
-		if (key == null)
-			return false;
-		if (ECLIPSE_CONTEXT_NAME.equals(key))
-			return (context != null);
-		return context.containsKey(key);
-	}
-
-	public Object get(ObjectDescriptor properties) {
-		String key = getKey(properties);
-		if (key == null)
-			return null;
-		if (ECLIPSE_CONTEXT_NAME.equals(key))
-			return context;
-		return context.get(key);
-	}
-
-	private String getKey(ObjectDescriptor descriptor) {
-		if (descriptor.hasQualifier(Named.class.getName()))
-			return descriptor.getQualifierValue(Named.class.getName());
-		Class elementClass = descriptor.getElementClass();
-		if (elementClass != null)
-			return elementClass.getName();
-		return null;
-	}
-
-	public String toString() {
-		return "ContextToInjectorLink(" + context + ')'; //$NON-NLS-1$
-	}
-
-	public IEclipseContext getContext() {
-		return context;
-	}
-
-	static public ObjectProviderContext getObjectProvider(IEclipseContext context) {
-		String key = ObjectProviderContext.class.getName();
-		if (context.containsKey(key, true))
-			return (ObjectProviderContext) context.get(key);
-		ObjectProviderContext objectProvider = new ObjectProviderContext(context);
-		context.set(key, objectProvider);
-		return objectProvider;
-	}
-
-	public void runAndTrack(final IRunAndTrack runnable, Object[] args) {
-		context.runAndTrack(runnable, args);
-	}
-
-	// TBD remove?
-	public boolean equals(Object obj) {
-		if (obj == this)
-			return true;
-		if (!(obj instanceof ObjectProviderContext))
-			return false;
-		return context.equals(((ObjectProviderContext) obj).context);
-	}
-
-	// TBD remove?
-	public int hashCode() {
-		return context.hashCode();
-	}
-
-}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ProviderImpl.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ProviderImpl.java
new file mode 100644
index 0000000..61dd4e4
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ProviderImpl.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import java.lang.reflect.InvocationTargetException;
+import javax.inject.Provider;
+import org.eclipse.e4.core.services.injector.AbstractObjectSupplier;
+import org.eclipse.e4.core.services.injector.IInjector;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+
+public class ProviderImpl<T> implements Provider<T> {
+
+	final private AbstractObjectSupplier objectProvider;
+	final private IObjectDescriptor objectDescriptor;
+	final private IInjector injector;
+
+	public ProviderImpl(IObjectDescriptor descriptor, IInjector injector,
+			AbstractObjectSupplier provider) {
+		objectDescriptor = descriptor;
+		objectProvider = provider;
+		this.injector = injector;
+	}
+
+	@SuppressWarnings("unchecked")
+	public T get() {
+		try {
+			return (T) injector.make(objectDescriptor, objectProvider);
+		} catch (ClassCastException e) {
+			return null;
+		} catch (InvocationTargetException e) {
+			// TBD add proper logging
+			e.printStackTrace();
+			return null;
+		} catch (InstantiationException e) {
+			// TBD add proper logging
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Requestor.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Requestor.java
new file mode 100644
index 0000000..bb5e53a
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/Requestor.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * 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.core.services.internal.context;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.e4.core.services.injector.IObjectDescriptor;
+import org.eclipse.e4.core.services.injector.IRequestor;
+import org.eclipse.e4.core.services.internal.annotations.AnnotationsSupport;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+abstract public class Requestor implements IRequestor {
+
+	final private WeakReference<Object> objectRef;
+	final private boolean track;
+	final private boolean groupUpdates;
+	final private boolean isOptional;
+
+	protected Object[] actualArgs;
+
+	// plug-in class that gets replaced in Java 1.5+
+	// TBD this will be merged-in; replace with an utility class
+	final protected AnnotationsSupport annotationSupport = new AnnotationsSupport();
+
+	public abstract IObjectDescriptor[] getDependentObjects();
+
+	public abstract Object execute() throws InvocationTargetException, InstantiationException;
+
+	public Requestor(Object requestingObject, boolean track, boolean groupUpdates,
+			boolean isOptional) {
+		if (requestingObject != null)
+			objectRef = new WeakReference<Object>(requestingObject);
+		else
+			objectRef = null;
+		this.track = track;
+		this.groupUpdates = groupUpdates;
+		this.isOptional = isOptional;
+	}
+
+	public Object getRequestingObject() {
+		if (objectRef == null)
+			return null;
+		return objectRef.get();
+	}
+
+	/**
+	 * Determines if the requestor wants to be called whenever one of the dependent object changes.
+	 * 
+	 * @return
+	 */
+	public boolean shouldTrack() {
+		return track;
+	}
+
+	public boolean shouldGroupUpdates() {
+		return groupUpdates;
+	}
+
+	public boolean isOptional() {
+		return isOptional;
+	}
+
+	/**
+	 * If actual arguments are resolved for this requestor
+	 */
+	public boolean isResolved() {
+		return (actualArgs != null);
+	}
+
+	public void setResolvedArgs(Object[] actualArgs) {
+		this.actualArgs = actualArgs;
+	}
+
+	protected void logError(Object destination, Exception e) {
+		String msg = "Injection failed " + destination.toString();
+		logError(msg, e);
+	}
+
+	protected void logError(String msg, Exception e) {
+		System.out.println(msg); //$NON-NLS-1$
+		if (e != null)
+			e.printStackTrace();
+		// TBD convert this into real logging
+		// String msg = NLS.bind("Injection failed", destination.toString());
+		// RuntimeLog.log(new Status(IStatus.WARNING,
+		// IRuntimeConstants.PI_COMMON, 0, msg, e));
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ValueComputation.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ValueComputation.java
index c193a08..1e09cf3 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ValueComputation.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/ValueComputation.java
@@ -14,7 +14,6 @@
 import org.eclipse.e4.core.services.context.ContextChangeEvent;
 import org.eclipse.e4.core.services.context.IContextFunction;
 import org.eclipse.e4.core.services.context.IEclipseContext;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 import org.eclipse.e4.core.services.internal.context.EclipseContext.Scheduled;
 
 public class ValueComputation extends Computation {
@@ -113,14 +112,14 @@
 		int eventType = event.getEventType();
 		// if the originating context is being disposed, remove this value computation completely
 		if (eventType == ContextChangeEvent.DISPOSE) {
-			IObjectProvider provider = event.getContext();
-			IEclipseContext eventsContext = ((ObjectProviderContext) provider).getContext();
+			IEclipseContext eventsContext = event.getContext();
 			if (originatingContext.equals(eventsContext)) {
 				removeAll(originatingContext);
 				return;
 			}
 		}
-		this.originatingContext.handleInvalid(this.name,
+		// this.originatingContext.handleInvalid(this.name,
+		((EclipseContext) this.originatingContext).invalidate(this.name,
 				eventType == ContextChangeEvent.DISPOSE ? ContextChangeEvent.REMOVED : eventType,
 				event.getOldValue(), scheduled);
 	}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/internal/core/services/osgi/OSGiContextStrategy.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/internal/core/services/osgi/OSGiContextStrategy.java
index 147aadf..4961c90 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/internal/core/services/osgi/OSGiContextStrategy.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/internal/core/services/osgi/OSGiContextStrategy.java
@@ -22,8 +22,6 @@
 import org.eclipse.e4.core.services.context.IRunAndTrack;
 import org.eclipse.e4.core.services.context.spi.IContextConstants;
 import org.eclipse.e4.core.services.context.spi.ILookupStrategy;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
-import org.eclipse.e4.core.services.internal.context.ObjectProviderContext;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
@@ -264,7 +262,7 @@
 	 * we can do appropriate cleanup of our caches when the requesting context is disposed.
 	 */
 	public boolean notify(ContextChangeEvent event) {
-		IEclipseContext context = getContext(event);
+		IEclipseContext context = event.getContext();
 		if (context == null)
 			return false;
 		if (event.getEventType() != ContextChangeEvent.DISPOSE) {
@@ -285,11 +283,4 @@
 		}
 		return true;
 	}
-
-	private IEclipseContext getContext(ContextChangeEvent event) {
-		IObjectProvider provider = event.getContext();
-		if (provider instanceof ObjectProviderContext)
-			return ((ObjectProviderContext) provider).getContext();
-		return null;
-	}
 }
diff --git a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ContextInjectionTest.java b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ContextInjectionTest.java
index f0f9674..21d2965 100644
--- a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ContextInjectionTest.java
+++ b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ContextInjectionTest.java
@@ -46,7 +46,7 @@
 
 			public TestData value;
 
-			public void contextSet(IEclipseContext context) {
+			public void inject__contextSet(IEclipseContext context) {
 				contextSetCalled++;
 			}
 
@@ -130,7 +130,7 @@
 		// check field injection
 		assertEquals(testString, userObject.inject__String);
 		assertEquals(testInt, userObject.getInt());
-		assertEquals(context, userObject.context);
+		// assertEquals(context, userObject.context);
 
 		// check method injection
 		assertEquals(1, userObject.setMethodCalled);
@@ -170,7 +170,7 @@
 		// check field injection
 		assertEquals(testString, userObject.inject__String);
 		assertEquals(testInt, userObject.getInt());
-		assertEquals(context, userObject.context);
+		// assertEquals(context, userObject.context);
 
 		// check method injection
 		assertEquals(1, userObject.setMethodCalled);
@@ -202,7 +202,7 @@
 
 		// check inherited portion
 		assertEquals(testString, userObject.getString());
-		assertEquals(context, userObject.getContext());
+		// assertEquals(context, userObject.getContext());
 		assertEquals(testString, userObject.getStringViaMethod());
 		assertEquals(1, userObject.setStringCalled);
 
diff --git a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ObjectBasic.java b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ObjectBasic.java
index 3f0c655..c424c54 100644
--- a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ObjectBasic.java
+++ b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/ObjectBasic.java
@@ -49,7 +49,7 @@
 		this.c = c;
 	}
 
-	public void contextSet(IEclipseContext context) {
+	public void inject__contextSet(IEclipseContext context) {
 		this.context = context;
 		finalized = true;
 	}
diff --git a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/RunAndTrackTest.java b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/RunAndTrackTest.java
index d923a2f..1a30d4f 100644
--- a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/RunAndTrackTest.java
+++ b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/RunAndTrackTest.java
@@ -22,7 +22,6 @@
 import org.eclipse.e4.core.services.context.IRunAndTrack;
 import org.eclipse.e4.core.services.context.spi.ContextFunction;
 import org.eclipse.e4.core.services.context.spi.IContextConstants;
-import org.eclipse.e4.core.services.injector.IObjectProvider;
 import org.eclipse.e4.core.tests.services.TestActivator;
 
 /**
@@ -132,8 +131,7 @@
 
 			public boolean notify(ContextChangeEvent event) {
 				oldValue = event.getOldValue();
-				IObjectProvider provider = event.getContext();
-				IEclipseContext eventsContext = ((ObjectProviderContext) provider).getContext();
+				IEclipseContext eventsContext = event.getContext();
 				newValue = eventsContext.get(NAME);
 				return true;
 			}
@@ -179,8 +177,7 @@
 			public boolean notify(ContextChangeEvent event) {
 				// must get a value so we aren't removed
 				eventType = event.getEventType();
-				IObjectProvider provider = event.getContext();
-				IEclipseContext eventsContext = ((ObjectProviderContext) provider).getContext();
+				IEclipseContext eventsContext = event.getContext();
 				eventsContext.get(NAME);
 				return true;
 			}