Bug 513563 - @Service annotation does not track optional references

Change-Id: I919e9a8999d486661669618e89e4a686ad0d9239
Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
index 9605f6c..cec3c74 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
@@ -6,15 +6,16 @@
 Bundle-Version: 0.15.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Require-Capability: osgi.extender;
-  filter:="(&(osgi.extender=osgi.component)(version>=1.2)(!(version>=2.0)))"
+  filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))"
 Import-Package: org.eclipse.core.runtime.preferences;version="3.3.0",
  org.eclipse.e4.core.di,
  org.eclipse.e4.core.di.annotations;version="1.6.0",
  org.eclipse.e4.core.di.extensions;version="0.15.0",
  org.eclipse.e4.core.di.suppliers,
  org.osgi.framework;version="1.8.0",
- org.osgi.service.component.annotations;version="1.2.0";resolution:=optional,
- org.osgi.service.event;version="1.3.0"
+ org.osgi.service.component.annotations;version="1.3.0";resolution:=optional,
+ org.osgi.service.event;version="1.3.0",
+ org.osgi.service.log;version="1.3.0"
 Service-Component: OSGI-INF/org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier.xml,
  OSGI-INF/org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier.xml,
  OSGI-INF/org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.xml,
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/p2.inf b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/p2.inf
index fbf82cf..0e2bd12 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/p2.inf
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/p2.inf
@@ -1,3 +1,3 @@
 requires.0.namespace = osgi.extender
 requires.0.name = osgi.component
-requires.0.range = [1.2.0, 2)
\ No newline at end of file
+requires.0.range = [1.3.0, 2)
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
index d00d972..22accb0 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014 BestSolution.at and others.
+ * Copyright (c) 2014, 2017 BestSolution.at 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 513563
  *******************************************************************************/
 package org.eclipse.e4.core.di.internal.extensions;
 
@@ -22,6 +23,7 @@
 import java.util.Set;
 import java.util.function.Predicate;
 import org.eclipse.e4.core.di.IInjector;
+import org.eclipse.e4.core.di.InjectionException;
 import org.eclipse.e4.core.di.extensions.Service;
 import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
 import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
@@ -35,6 +37,9 @@
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.log.LogService;
 
 /**
  * Supplier for {@link Service}
@@ -42,6 +47,9 @@
 @Component(service = ExtendedObjectSupplier.class, property = "dependency.injection.annotation:String=org.eclipse.e4.core.di.extensions.Service")
 public class ServiceSupplier extends ExtendedObjectSupplier {
 
+	@Reference(cardinality = ReferenceCardinality.OPTIONAL)
+	volatile LogService logService;
+
 	static class ServiceHandler implements ServiceListener {
 		private final ServiceSupplier supplier;
 		final Set<IRequestor> requestors = new HashSet<>();
@@ -81,8 +89,8 @@
 							try {
 								r.resolveArguments(false);
 								r.execute();
-							} catch(Throwable t) {
-								t.printStackTrace();
+							} catch (InjectionException e) {
+								this.supplier.logError("Injection failed", e); //$NON-NLS-1$
 							}
 						});
 						break;
@@ -119,28 +127,29 @@
 
 		@SuppressWarnings("unchecked")
 		Class<Object> cl = t instanceof ParameterizedType ? (Class<Object>) ((ParameterizedType) t).getRawType() : (Class<Object>) t;
+		Object result = IInjector.NOT_A_VALUE;
 		try {
-			{
-				String filter = qualifier.filterExpression() != null && ! qualifier.filterExpression().isEmpty() ? qualifier.filterExpression() : null;
+			String filter = qualifier.filterExpression() != null && !qualifier.filterExpression().isEmpty()
+					? qualifier.filterExpression()
+					: null;
 
-				ServiceReference<?>[] serviceReferences = context.getServiceReferences(cl.getName(), filter);
-				if( serviceReferences != null ) {
-					Arrays.sort(serviceReferences);
+			ServiceReference<?>[] serviceReferences = context.getServiceReferences(cl.getName(), filter);
+			if (serviceReferences != null) {
+				Arrays.sort(serviceReferences);
 
-					if( serviceReferences.length > 0 ) {
-						if( track ) {
-							trackService(context, cl, requestor);
-						}
-						return context.getService(serviceReferences[serviceReferences.length-1]);
-					}
+				if (serviceReferences.length > 0) {
+					result = context.getService(serviceReferences[serviceReferences.length - 1]);
 				}
 			}
 		} catch (InvalidSyntaxException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
+			logError("Invalid filter expression", e); //$NON-NLS-1$
 		}
 
-		return IInjector.NOT_A_VALUE;
+		if (track) {
+			trackService(context, cl, requestor);
+		}
+
+		return result;
 	}
 
 	private List<Object> handleCollection(Bundle bundle, Type t, IRequestor requestor, boolean track, Service qualifier) {
@@ -168,12 +177,11 @@
 			// We are in the wrong order
 			Collections.reverse(rv);
 
-			if( track ) {
+			if (track) {
 				trackService(context, cl, requestor);
 			}
 		} catch (InvalidSyntaxException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
+			logError("Invalid filter expression", e); //$NON-NLS-1$
 		}
 
 		return rv;
@@ -188,4 +196,22 @@
 		});
 		handler.requestors.add(requestor);
 	}
+
+	/**
+	 * Method to log an exception.
+	 * 
+	 * @param message
+	 *            The log message.
+	 * @param e
+	 *            The exception that should be logged.
+	 */
+	void logError(String message, Throwable e) {
+		if (this.logService != null) {
+			this.logService.log(LogService.LOG_ERROR, message, e);
+		} else {
+			// fallback if no LogService is available
+			e.printStackTrace();
+		}
+	}
+
 }
diff --git a/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF
index 4de7d8a..40f7fc4 100644
--- a/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF
@@ -19,7 +19,8 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.annotation,
  javax.inject;version="1.0.0",
- org.osgi.service.component.annotations;version="1.2.0";resolution:=optional,
+ org.osgi.service.component;version="1.3.0",
+ org.osgi.service.component.annotations;version="1.3.0";resolution:=optional,
  org.osgi.service.event;version="1.3.0"
 Export-Package: org.eclipse.e4.core.internal.tests;x-internal:=true,
  org.eclipse.e4.core.internal.tests.contexts;x-internal:=true,
@@ -34,10 +35,13 @@
  OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.FilterServiceA.xml,
  OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.FilterServiceB.xml,
  OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.SampleServiceA.xml,
- OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.SampleServiceB.xml
+ OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.SampleServiceB.xml,
+ OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler.xml,
+ OSGI-INF/DisabledServiceA.xml,
+ OSGI-INF/DisabledServiceB.xml
 Eclipse-BundleShape: dir
 Require-Capability: osgi.extender;
-  filter:="(&(osgi.extender=osgi.component)(version>=1.2)(!(version>=2.0)))",
+  filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))",
  osgi.service;
   filter:="(objectClass=org.osgi.service.event.EventAdmin)";
   effective:="active"
diff --git a/tests/org.eclipse.e4.core.tests/META-INF/p2.inf b/tests/org.eclipse.e4.core.tests/META-INF/p2.inf
index b134fe5..a692193 100644
--- a/tests/org.eclipse.e4.core.tests/META-INF/p2.inf
+++ b/tests/org.eclipse.e4.core.tests/META-INF/p2.inf
@@ -1,5 +1,5 @@
 requires.0.namespace = osgi.extender
 requires.0.name = osgi.component
-requires.0.range = [1.2.0, 2)
+requires.0.range = [1.3.0, 2)
 requires.1.namespace = osgi.service
 requires.1.name = org.osgi.service.event.EventAdmin
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceA.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceA.xml
new file mode 100644
index 0000000..580c779
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceA.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" enabled="false" name="DisabledServiceA">
+   <property name="component" value="disabled"/>
+   <service>
+      <provide interface="org.eclipse.e4.core.internal.tests.di.extensions.TestService"/>
+   </service>
+   <implementation class="org.eclipse.e4.core.internal.tests.di.extensions.DisabledServiceA"/>
+</scr:component>
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceB.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceB.xml
new file mode 100644
index 0000000..4d9add3
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/DisabledServiceB.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" enabled="false" name="DisabledServiceB">
+   <property name="component" value="disabled"/>
+   <property name="service.ranking" type="Integer" value="5"/>
+   <service>
+      <provide interface="org.eclipse.e4.core.internal.tests.di.extensions.TestService"/>
+   </service>
+   <implementation class="org.eclipse.e4.core.internal.tests.di.extensions.DisabledServiceB"/>
+</scr:component>
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler.xml
new file mode 100644
index 0000000..5392911
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" name="org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler">
+   <service>
+      <provide interface="org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler"/>
+   </service>
+   <implementation class="org.eclipse.e4.core.internal.tests.di.extensions.ComponentEnabler"/>
+</scr:component>
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ComponentEnabler.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ComponentEnabler.java
new file mode 100644
index 0000000..84288f4
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ComponentEnabler.java
@@ -0,0 +1,32 @@
+package org.eclipse.e4.core.internal.tests.di.extensions;
+
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = ComponentEnabler.class)
+public class ComponentEnabler {
+
+	ComponentContext context;
+
+	@Activate
+	void activate(ComponentContext context) {
+		this.context = context;
+	}
+
+	public void enableDisabledServiceA() {
+		this.context.enableComponent("DisabledServiceA");
+	}
+
+	public void disableDisabledServiceA() {
+		this.context.disableComponent("DisabledServiceA");
+	}
+
+	public void enableDisabledServiceB() {
+		this.context.enableComponent("DisabledServiceB");
+	}
+
+	public void disableDisabledServiceB() {
+		this.context.disableComponent("DisabledServiceB");
+	}
+}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceA.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceA.java
new file mode 100644
index 0000000..02f9a9d
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceA.java
@@ -0,0 +1,8 @@
+package org.eclipse.e4.core.internal.tests.di.extensions;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(name = "DisabledServiceA", enabled = false, property = { "component=disabled" })
+public class DisabledServiceA implements TestService {
+
+}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceB.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceB.java
new file mode 100644
index 0000000..7f2f864
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/DisabledServiceB.java
@@ -0,0 +1,8 @@
+package org.eclipse.e4.core.internal.tests.di.extensions;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(name = "DisabledServiceB", enabled = false, property = { "component=disabled", "service.ranking:Integer=5" })
+public class DisabledServiceB implements TestService {
+
+}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ServiceSupplierTestCase.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ServiceSupplierTestCase.java
index b761e4f..00d6733 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ServiceSupplierTestCase.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/ServiceSupplierTestCase.java
@@ -1,5 +1,10 @@
 package org.eclipse.e4.core.internal.tests.di.extensions;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
@@ -9,12 +14,13 @@
 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
 import org.eclipse.e4.core.contexts.EclipseContextFactory;
 import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.core.di.extensions.Service;
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Test;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 
 public class ServiceSupplierTestCase {
@@ -56,6 +62,17 @@
 		}
 	}
 
+	public static class TestDisabledBean {
+		@Inject
+		@Optional
+		@Service(filterExpression = "(component=disabled)")
+		TestService disabledService;
+
+		@Inject
+		@Service(filterExpression = "(component=disabled)")
+		List<TestService> services;
+	}
+
 	private List<ServiceRegistration<?>> registrations = new ArrayList<>();
 
 	@After
@@ -67,15 +84,15 @@
 	public void testInitialInject() {
 		IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(FrameworkUtil.getBundle(getClass()).getBundleContext());
 		TestBean bean = ContextInjectionFactory.make(TestBean.class, serviceContext);
-		Assert.assertNotNull(bean.service);
-		Assert.assertNotNull(bean.serviceList);
-		Assert.assertSame(SampleServiceA.class,bean.service.getClass());
-		Assert.assertEquals(1, bean.serviceInjectionCount);
+		assertNotNull(bean.service);
+		assertNotNull(bean.serviceList);
+		assertSame(SampleServiceA.class, bean.service.getClass());
+		assertEquals(1, bean.serviceInjectionCount);
 
-		Assert.assertEquals(4, bean.serviceList.size());
-		Assert.assertEquals(1, bean.serviceListInjectionCount);
-		Assert.assertSame(SampleServiceA.class,bean.serviceList.get(0).getClass());
-		Assert.assertSame(SampleServiceB.class,bean.serviceList.get(1).getClass());
+		assertEquals(4, bean.serviceList.size());
+		assertEquals(1, bean.serviceListInjectionCount);
+		assertSame(SampleServiceA.class, bean.serviceList.get(0).getClass());
+		assertSame(SampleServiceB.class, bean.serviceList.get(1).getClass());
 
 	}
 
@@ -84,16 +101,16 @@
 		IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(FrameworkUtil.getBundle(getClass()).getBundleContext());
 		TestStaticFilterBean bean = ContextInjectionFactory.make(TestStaticFilterBean.class, serviceContext);
 
-		Assert.assertNotNull(bean.service);
-		Assert.assertNotNull(bean.serviceList);
+		assertNotNull(bean.service);
+		assertNotNull(bean.serviceList);
 
-		Assert.assertSame(FilterServiceA.class,bean.service.getClass());
-		Assert.assertEquals(1, bean.serviceInjectionCount);
+		assertSame(FilterServiceA.class, bean.service.getClass());
+		assertEquals(1, bean.serviceInjectionCount);
 
-		Assert.assertEquals(2, bean.serviceList.size());
-		Assert.assertEquals(1, bean.serviceListInjectionCount);
-		Assert.assertSame(FilterServiceA.class,bean.serviceList.get(0).getClass());
-		Assert.assertSame(FilterServiceB.class,bean.serviceList.get(1).getClass());
+		assertEquals(2, bean.serviceList.size());
+		assertEquals(1, bean.serviceListInjectionCount);
+		assertSame(FilterServiceA.class, bean.serviceList.get(0).getClass());
+		assertSame(FilterServiceB.class, bean.serviceList.get(1).getClass());
 	}
 
 	@Test
@@ -102,8 +119,8 @@
 		IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(context);
 		TestBean bean = ContextInjectionFactory.make(TestBean.class, serviceContext);
 
-		Assert.assertEquals(1, bean.serviceInjectionCount);
-		Assert.assertEquals(1, bean.serviceListInjectionCount);
+		assertEquals(1, bean.serviceInjectionCount);
+		assertEquals(1, bean.serviceListInjectionCount);
 
 		TestService t = new TestService() {
 			// nothing todo
@@ -113,12 +130,12 @@
 		properties.put("service.ranking", 100); //$NON-NLS-1$
 		this.registrations.add(context.registerService(TestService.class, t, properties));
 
-		Assert.assertSame(t,bean.service);
-		Assert.assertEquals(2, bean.serviceInjectionCount);
+		assertSame(t, bean.service);
+		assertEquals(2, bean.serviceInjectionCount);
 
-		Assert.assertEquals(2, bean.serviceListInjectionCount);
-		Assert.assertEquals(5, bean.serviceList.size());
-		Assert.assertSame(t,bean.serviceList.get(0));
+		assertEquals(2, bean.serviceListInjectionCount);
+		assertEquals(5, bean.serviceList.size());
+		assertSame(t, bean.serviceList.get(0));
 
 		TestService t2 = new TestService() {
 			// nothing todo
@@ -128,13 +145,13 @@
 		properties.put("service.ranking", Integer.valueOf(-1)); //$NON-NLS-1$
 		this.registrations.add(context.registerService(TestService.class, t2, properties));
 
-		Assert.assertSame(t,bean.service);
-		Assert.assertEquals(3, bean.serviceInjectionCount);
+		assertSame(t, bean.service);
+		assertEquals(3, bean.serviceInjectionCount);
 
-		Assert.assertEquals(3, bean.serviceListInjectionCount);
+		assertEquals(3, bean.serviceListInjectionCount);
 
-		Assert.assertEquals(6, bean.serviceList.size());
-		Assert.assertSame(t,bean.serviceList.get(0));
+		assertEquals(6, bean.serviceList.size());
+		assertSame(t, bean.serviceList.get(0));
 	}
 
 	@Test
@@ -143,8 +160,8 @@
 		IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(context);
 		TestBean bean = ContextInjectionFactory.make(TestBean.class, serviceContext);
 
-		Assert.assertEquals(1, bean.serviceInjectionCount);
-		Assert.assertEquals(1, bean.serviceListInjectionCount);
+		assertEquals(1, bean.serviceInjectionCount);
+		assertEquals(1, bean.serviceListInjectionCount);
 
 		TestService t = new TestService() {
 			// nothing todo
@@ -154,24 +171,24 @@
 		properties.put("service.ranking", 52); //$NON-NLS-1$
 		this.registrations.add(context.registerService(TestService.class, t, properties));
 
-		Assert.assertSame(t,bean.service);
-		Assert.assertEquals(2, bean.serviceInjectionCount);
+		assertSame(t, bean.service);
+		assertEquals(2, bean.serviceInjectionCount);
 
-		Assert.assertEquals(2, bean.serviceListInjectionCount);
-		Assert.assertEquals(5, bean.serviceList.size());
-		Assert.assertSame(t,bean.serviceList.get(0));
+		assertEquals(2, bean.serviceListInjectionCount);
+		assertEquals(5, bean.serviceList.size());
+		assertSame(t, bean.serviceList.get(0));
 
 		ServiceRegistration<?> registration = this.registrations.get(0);
 		registration.unregister();
 		this.registrations.remove(registration);
 
-		Assert.assertEquals(3, bean.serviceInjectionCount);
-		Assert.assertEquals(3, bean.serviceListInjectionCount);
+		assertEquals(3, bean.serviceInjectionCount);
+		assertEquals(3, bean.serviceListInjectionCount);
 
-		Assert.assertSame(SampleServiceA.class,bean.service.getClass());
-		Assert.assertEquals(4, bean.serviceList.size());
-		Assert.assertSame(SampleServiceA.class,bean.serviceList.get(0).getClass());
-		Assert.assertSame(SampleServiceB.class,bean.serviceList.get(1).getClass());
+		assertSame(SampleServiceA.class, bean.service.getClass());
+		assertEquals(4, bean.serviceList.size());
+		assertSame(SampleServiceA.class, bean.serviceList.get(0).getClass());
+		assertSame(SampleServiceB.class, bean.serviceList.get(1).getClass());
 	}
 
 	@Test
@@ -189,6 +206,53 @@
 		properties.put("service.ranking", 2); //$NON-NLS-1$
 		this.registrations.add(context.registerService(TestService.class, t, properties));
 
-		Assert.assertSame(SampleServiceA.class,bean.service.getClass());
+		assertSame(SampleServiceA.class, bean.service.getClass());
+	}
+
+	@Test
+	public void testOptionalReferences() throws InterruptedException {
+		BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+		IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(context);
+		TestDisabledBean bean = ContextInjectionFactory.make(TestDisabledBean.class, serviceContext);
+
+		assertNull(bean.disabledService);
+		assertEquals(0, bean.services.size());
+
+		ServiceReference<ComponentEnabler> ref = context.getServiceReference(ComponentEnabler.class);
+		ComponentEnabler enabler = context.getService(ref);
+		try {
+			enabler.enableDisabledServiceA();
+			// give the service registry and the injection some time
+			Thread.sleep(100);
+			assertNotNull(bean.disabledService);
+			assertEquals(1, bean.services.size());
+			assertSame(DisabledServiceA.class, bean.disabledService.getClass());
+
+			enabler.enableDisabledServiceB();
+			// give the service registry and the injection some time
+			Thread.sleep(100);
+			assertNotNull(bean.disabledService);
+			assertEquals(2, bean.services.size());
+			assertSame(DisabledServiceB.class, bean.disabledService.getClass());
+
+			enabler.disableDisabledServiceB();
+			// give the service registry and the injection some time
+			Thread.sleep(100);
+			assertNotNull(bean.disabledService);
+			assertEquals(1, bean.services.size());
+			assertSame(DisabledServiceA.class, bean.disabledService.getClass());
+
+			enabler.disableDisabledServiceA();
+			// give the service registry and the injection some time
+			Thread.sleep(100);
+			assertNull(bean.disabledService);
+			assertEquals(0, bean.services.size());
+		} finally {
+			enabler.disableDisabledServiceA();
+			enabler.disableDisabledServiceB();
+			// give the service registry and the injection some time to ensure
+			// clear state after this test
+			Thread.sleep(100);
+		}
 	}
 }