diff options
11 files changed, 224 insertions, 26 deletions
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/osgi/EclipseContextOSGi.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/osgi/EclipseContextOSGi.java index 1167d7c3c..149227101 100644 --- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/osgi/EclipseContextOSGi.java +++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/osgi/EclipseContextOSGi.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2011, 2015 IBM Corporation and others.
+ * Copyright (c) 2011, 2017 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
@@ -87,13 +87,6 @@ public class EclipseContextOSGi extends EclipseContext implements ServiceListene return service;
}
- /**
- * Returns the service name for a service reference
- */
- private String serviceName(ServiceReference<?> reference) {
- return ((String[]) reference.getProperty(Constants.OBJECTCLASS))[0];
- }
-
@Override
public void dispose() {
for (ServiceReference<?> ref : refs.values()) {
@@ -109,21 +102,29 @@ public class EclipseContextOSGi extends EclipseContext implements ServiceListene @Override
public void serviceChanged(ServiceEvent event) {
ServiceReference<?> ref = event.getServiceReference();
- String name = serviceName(ref);
- if (IContextFunction.SERVICE_NAME.equals(name)) // those keep associated names
- name = (String) ref.getProperty(IContextFunction.SERVICE_CONTEXT_KEY);
+ String[] names = ((String[]) ref.getProperty(Constants.OBJECTCLASS));
+ for (String name : names) {
+ if (IContextFunction.SERVICE_NAME.equals(name)) {
+ name = (String) ref.getProperty(IContextFunction.SERVICE_CONTEXT_KEY);
+ }
+
+ if (refs.containsKey(name)) {
+ // retrieve the highest ranked service of the same type
+ ref = bundleContext.getServiceReference(name);
- if (refs.containsKey(name)) {
- ServiceReference<?> oldRef = refs.get(name);
- if (oldRef != null)
- bundleContext.ungetService(oldRef);
- if (event.getType() == ServiceEvent.UNREGISTERING) {
- refs.put(name, null);
- remove(name);
- } else {
- Object service = bundleContext.getService(ref);
- refs.put(name, ref);
- set(name, service);
+ ServiceReference<?> oldRef = refs.get(name);
+ if (oldRef != null && oldRef != ref) {
+ bundleContext.ungetService(oldRef);
+ }
+
+ if (ref != null) {
+ Object service = bundleContext.getService(ref);
+ refs.put(name, ref);
+ set(name, service);
+ } else {
+ refs.put(name, null);
+ remove(name);
+ }
}
}
}
@@ -131,8 +132,9 @@ public class EclipseContextOSGi extends EclipseContext implements ServiceListene @Override
public void bundleChanged(BundleEvent event) {
// In case OSGi context has not being properly disposed by the application,
- // OSGi framework shutdown will trigged uninjection of all consumed OSGi
- // service. To avoid this, we detect framework shutdown and release services.
+ // OSGi framework shutdown will triggered uninjection of all consumed
+ // OSGi service. To avoid this, we detect framework shutdown and release
+ // services.
if (event.getType() != BundleEvent.STOPPING)
return;
if (event.getBundle().getBundleId() == 0)
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 40f7fc430..3dafa7eb6 100644 --- a/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.e4.core.tests/META-INF/MANIFEST.MF @@ -38,7 +38,10 @@ Service-Component: OSGI-INF/adder.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 + OSGI-INF/DisabledServiceB.xml, + OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceController.xml, + OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA.xml, + OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceB.xml Eclipse-BundleShape: dir Require-Capability: osgi.extender; filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))", diff --git a/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA.xml new file mode 100644 index 000000000..7cf23f5e6 --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA.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="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA"> + <service> + <provide interface="org.eclipse.e4.core.internal.tests.contexts.inject.TestService"/> + <provide interface="org.eclipse.e4.core.internal.tests.contexts.inject.TestOtherService"/> + </service> + <implementation class="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceA"/> +</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.contexts.inject.TestServiceB.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceB.xml new file mode 100644 index 000000000..bed59849e --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceB.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="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceB"> + <property name="service.ranking" type="Integer" value="5"/> + <service> + <provide interface="org.eclipse.e4.core.internal.tests.contexts.inject.TestService"/> + <provide interface="org.eclipse.e4.core.internal.tests.contexts.inject.TestOtherService"/> + </service> + <implementation class="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceB"/> +</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.contexts.inject.TestServiceController.xml b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceController.xml new file mode 100644 index 000000000..f5a8db8ba --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/OSGI-INF/org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceController.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.contexts.inject.TestServiceController"> + <service> + <provide interface="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceController"/> + </service> + <implementation class="org.eclipse.e4.core.internal.tests.contexts.inject.TestServiceController"/> +</scr:component>
\ No newline at end of file diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ServiceContextTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ServiceContextTest.java index 98f655efd..06e374041 100644 --- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ServiceContextTest.java +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ServiceContextTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2015 IBM Corporation and others. + * Copyright (c) 2009, 2017 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 @@ -15,6 +15,7 @@ package org.eclipse.e4.core.internal.tests.contexts.inject; 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 static org.junit.Assert.assertTrue; import java.util.ArrayList; @@ -34,6 +35,7 @@ import org.junit.Before; import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; @@ -88,6 +90,16 @@ public class ServiceContextTest { } } + static class TestBean { + @Inject + @Optional + TestService testService; + + @Inject + @Optional + TestOtherService testOtherService; + } + private IEclipseContext context; private final List<ServiceRegistration<?>> registrations = new ArrayList<>(); @@ -277,4 +289,103 @@ public class ServiceContextTest { crayon.draw(); } + @Test + public void testOptionalReferences() throws InterruptedException { + BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext(); + IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(context); + TestBean bean = ContextInjectionFactory.make(TestBean.class, serviceContext); + + assertNull(bean.testService); + + ServiceReference<TestServiceController> ref = context.getServiceReference(TestServiceController.class); + TestServiceController controller = context.getService(ref); + try { + controller.enableTestServiceA(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + assertSame(TestServiceA.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceA.class, bean.testOtherService.getClass()); + + controller.enableTestServiceB(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + assertSame(TestServiceB.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceB.class, bean.testOtherService.getClass()); + + controller.disableTestServiceB(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + assertSame(TestServiceA.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceA.class, bean.testOtherService.getClass()); + + controller.disableTestServiceA(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNull(bean.testService); + assertNull(bean.testOtherService); + } finally { + controller.disableTestServiceA(); + controller.disableTestServiceB(); + // give the service registry and the injection some time to ensure + // clear state after this test + Thread.sleep(100); + } + } + + @Test + public void testServiceRanking() throws InterruptedException { + BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext(); + IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(context); + TestBean bean = ContextInjectionFactory.make(TestBean.class, serviceContext); + + assertNull(bean.testService); + + ServiceReference<TestServiceController> ref = context.getServiceReference(TestServiceController.class); + TestServiceController controller = context.getService(ref); + try { + controller.enableTestServiceB(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + assertSame(TestServiceB.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceB.class, bean.testOtherService.getClass()); + + // enable a service with a lower ranking + controller.enableTestServiceA(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + // we expect that still the highest ranked service is injected + assertSame(TestServiceB.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceB.class, bean.testOtherService.getClass()); + + controller.disableTestServiceB(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNotNull(bean.testService); + assertSame(TestServiceA.class, bean.testService.getClass()); + assertNotNull(bean.testOtherService); + assertSame(TestServiceA.class, bean.testOtherService.getClass()); + + controller.disableTestServiceA(); + // give the service registry and the injection some time + Thread.sleep(100); + assertNull(bean.testService); + assertNull(bean.testOtherService); + } finally { + controller.disableTestServiceA(); + controller.disableTestServiceB(); + // give the service registry and the injection some time to ensure + // clear state after this test + Thread.sleep(100); + } + } } diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestOtherService.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestOtherService.java new file mode 100644 index 000000000..b983f3084 --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestOtherService.java @@ -0,0 +1,5 @@ +package org.eclipse.e4.core.internal.tests.contexts.inject; + +public interface TestOtherService { + +} diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestService.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestService.java new file mode 100644 index 000000000..11f52fabd --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestService.java @@ -0,0 +1,5 @@ +package org.eclipse.e4.core.internal.tests.contexts.inject; + +public interface TestService { + +} diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceA.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceA.java new file mode 100644 index 000000000..aa1eac4f0 --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceA.java @@ -0,0 +1,8 @@ +package org.eclipse.e4.core.internal.tests.contexts.inject; + +import org.osgi.service.component.annotations.Component; + +@Component(enabled = false) +public class TestServiceA implements TestService, TestOtherService { + +} diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceB.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceB.java new file mode 100644 index 000000000..32df30315 --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceB.java @@ -0,0 +1,8 @@ +package org.eclipse.e4.core.internal.tests.contexts.inject; + +import org.osgi.service.component.annotations.Component; + +@Component(enabled = false, property = "service.ranking:Integer=5") +public class TestServiceB implements TestService, TestOtherService { + +} diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceController.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceController.java new file mode 100644 index 000000000..6873ed636 --- /dev/null +++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/TestServiceController.java @@ -0,0 +1,32 @@ +package org.eclipse.e4.core.internal.tests.contexts.inject; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; + +@Component(service = TestServiceController.class) +public class TestServiceController { + + ComponentContext context; + + @Activate + void activate(ComponentContext context) { + this.context = context; + } + + public void enableTestServiceA() { + this.context.enableComponent(TestServiceA.class.getName()); + } + + public void disableTestServiceA() { + this.context.disableComponent(TestServiceA.class.getName()); + } + + public void enableTestServiceB() { + this.context.enableComponent(TestServiceB.class.getName()); + } + + public void disableTestServiceB() { + this.context.disableComponent(TestServiceB.class.getName()); + } +} |