Bug 423212: Allow to inject OSGi Bundle and BundleContext
- Rename @BundleContext to @OSGiBundle to prevent name clash between
parameter type and annotation.
- Support to inject org.osgi.framework.Bundle type, which is injectable
even if bundle's state is RESOLVED.
Bug-URL: https://bugs.eclipse.org/423212
Change-Id: I286010ab5f720d119b8c938409f131bfa87454d8
Signed-off-by: Markus Alexander Kuppe <bugs.eclipse.org@lemmster.de>
diff --git a/bundles/org.eclipse.e4.core.di.extensions/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.di.extensions/META-INF/MANIFEST.MF
index 2661a74..069557c 100644
--- a/bundles/org.eclipse.e4.core.di.extensions/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.core.di.extensions/META-INF/MANIFEST.MF
@@ -14,7 +14,7 @@
Import-Package: javax.annotation;version="1.0.0",
javax.inject;version="1.0.0"
Service-Component: OSGI-INF/preferences.xml, OSGI-INF/events.xml,
- OSGI-INF/bundleContext.xml
+ OSGI-INF/osgiBundle.xml
Export-Package: org.eclipse.e4.core.di.extensions;x-internal:=true,
org.eclipse.e4.core.di.internal.extensions;x-friends:="org.eclipse.e4.ui.di"
Bundle-Localization: fragment
diff --git a/bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/bundleContext.xml b/bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/osgiBundle.xml
similarity index 81%
rename from bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/bundleContext.xml
rename to bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/osgiBundle.xml
index a03d46c..9ceae67 100644
--- a/bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/bundleContext.xml
+++ b/bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/osgiBundle.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.core.di.extensions.bundleContext">
- <implementation class="org.eclipse.e4.core.di.internal.extensions.BundleContextObjectSupplier"/>
- <property name="dependency.injection.annotation" type="String" value="org.eclipse.e4.core.di.extensions.BundleContext"/>
+ <implementation class="org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier"/>
+ <property name="dependency.injection.annotation" type="String" value="org.eclipse.e4.core.di.extensions.OSGiBundle"/>
<service>
<provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
</service>
diff --git a/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/BundleContext.java b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/OSGiBundle.java
similarity index 63%
rename from bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/BundleContext.java
rename to bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/OSGiBundle.java
index d5e29fe..3a16936 100644
--- a/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/BundleContext.java
+++ b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/OSGiBundle.java
@@ -15,15 +15,22 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
/**
- * A method or field annotated with {@link BundleContext} will be injected with the
- * {@link org.osgi.framework.BundleContext} from the bundle contain the class.
+ * A method or field of type {@link org.osgi.framework.BundleContext} and
+ * annotated with {@link OSGiBundle} will be injected with the from the bundle
+ * containing the class if the annotated type is a {@link BundleContext}
+ * and the bundle's state is {@link Bundle#ACTIVE}.
+ * <p>
+ * If the method or field type is of {@link Bundle}, the bundle containing
+ * the class will be injected even for bundles in the {@link Bundle#RESOLVED} state.
*/
@Qualifier
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
-public @interface BundleContext {
+public @interface OSGiBundle {
// Nop
}
diff --git a/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/BundleContextObjectSupplier.java b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
similarity index 63%
rename from bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/BundleContextObjectSupplier.java
rename to bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
index f2547e4..cde905c 100644
--- a/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/BundleContextObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
@@ -9,6 +9,7 @@
******************************************************************************/
package org.eclipse.e4.core.di.internal.extensions;
+import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.e4.core.di.InjectionException;
@@ -23,37 +24,49 @@
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.SynchronousBundleListener;
-public class BundleContextObjectSupplier extends ExtendedObjectSupplier {
+public class OSGiObjectSupplier extends ExtendedObjectSupplier {
/**
* A Map of Requestor to BundleListener. Each Requestor will only ever request its own bundle and thus there is a 1:1 relationship between R and BL.
*/
private final Map<IRequestor, BundleListener> requestor2listener = new HashMap<IRequestor, BundleListener>();
- private final BundleContext localBundleContext = FrameworkUtil.getBundle(BundleContextObjectSupplier.class).getBundleContext();
+ private final BundleContext localBundleContext = FrameworkUtil.getBundle(OSGiObjectSupplier.class).getBundleContext();
@Override
public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
final Class<?> requestingObjectClass = requestor.getRequestingObjectClass();
- final Bundle bundle = FrameworkUtil.getBundle(requestingObjectClass);
- // Cannot use BundleListener as a BL can only be registered with a BC (which might be null)
- if (track) {
- if (!requestor2listener.containsKey(requestor)) {
- track(bundle, requestor);
+ final Type desiredType = descriptor.getDesiredType();
+ if (BundleContext.class.equals(desiredType)) {
+ final Bundle bundle = FrameworkUtil.getBundle(requestingObjectClass);
+
+ // Cannot use BundleListener as a BL can only be registered with a BC (which might be null)
+ if (track) {
+ if (!requestor2listener.containsKey(requestor)) {
+ track(bundle, requestor);
+ }
+ } else {
+ untrack(requestor);
}
- } else {
- untrack(requestor);
- }
- final BundleContext bundleContext = bundle.getBundleContext();
- if (bundleContext != null) {
- return bundleContext;
- } else if (descriptor.getQualifier(Optional.class) != null) {
- // Do not have a bundle context but requestor has marked the parameter/field optional
- return null;
+ final BundleContext bundleContext = bundle.getBundleContext();
+ if (bundleContext != null) {
+ return bundleContext;
+ } else if (descriptor.getQualifier(Optional.class) != null) {
+ // Do not have a bundle context but requestor has marked the parameter/field optional
+ return null;
+ }
+ throw new InjectionException("Unable to inject BundleContext: " + bundle.getSymbolicName() + " bundle is not active or starting/stopping"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else if (Bundle.class.equals(desiredType)) {
+ // Not tracking the Bundle's life-cycle because the B instance does
+ // not change whether a bundle is ACTIVE or RESOLVED. The only
+ // thing worth tracking is when a bundle switches to the INSTALLED
+ // state. However, the requestor will go away along with its bundle anyway.
+ return FrameworkUtil.getBundle(requestingObjectClass);
}
- throw new InjectionException("Unable to inject BundleContext: " + bundle.getSymbolicName() + " bundle is not active or starting/stopping"); //$NON-NLS-1$ //$NON-NLS-2$
+ // Annotation used with unsupported type
+ return null;
}
private void untrack(final IRequestor requestor) {
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionBundleContextTest.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionOSGiTest.java
similarity index 63%
rename from tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionBundleContextTest.java
rename to tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionOSGiTest.java
index 9a09a21..eb9ac08 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionBundleContextTest.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionOSGiTest.java
@@ -17,21 +17,22 @@
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.BundleContext;
+import org.eclipse.e4.core.di.extensions.OSGiBundle;
import org.eclipse.e4.core.internal.tests.CoreTestsActivator;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
-public class InjectionBundleContextTest extends TestCase {
+public class InjectionOSGiTest extends TestCase {
- // classed used as a user of the @BundleContext annotation
+ // classed used as a user of the @OSGiBundle annotation
static class InjectionTarget {
- private org.osgi.framework.BundleContext ctx;
+ private BundleContext ctx;
@Inject
public void setBundleContext(
- @BundleContext @Optional org.osgi.framework.BundleContext ctx) {
+ @OSGiBundle @Optional BundleContext ctx) {
this.ctx = ctx;
}
@@ -39,9 +40,30 @@
return this.ctx != null;
}
- public org.osgi.framework.BundleContext getContext() {
+ public BundleContext getContext() {
return this.ctx;
}
+
+ private Bundle b;
+
+ @Inject
+ public void setBundle(
+ @OSGiBundle Bundle b) {
+ this.b = b;
+ }
+
+ public Bundle getBundle() {
+ return this.b;
+ }
+
+ @Inject
+ public void setFoo(@OSGiBundle Object o) {
+ // make sure we don't fail when incompatible type requested
+ }
+ }
+
+ // classed used as a user of the @OSGiBundle annotation
+ static class InjectionBundleTarget extends InjectionTarget {
}
private InjectionTarget target;
@@ -51,7 +73,7 @@
protected void tearDown() throws Exception {
bundle.start();
- final org.osgi.framework.BundleContext bundleContext = CoreTestsActivator
+ final BundleContext bundleContext = CoreTestsActivator
.getDefault().getBundleContext();
final IEclipseContext localContext = EclipseContextFactory
.getServiceContext(bundleContext);
@@ -65,7 +87,7 @@
protected void setUp() throws Exception {
super.setUp();
- final org.osgi.framework.BundleContext bundleContext = CoreTestsActivator
+ final BundleContext bundleContext = CoreTestsActivator
.getDefault().getBundleContext();
bundle = bundleContext.getBundle();
@@ -85,7 +107,7 @@
assertTrue(target.hasContext());
// Check also that the BundleContext instance has indeed changed
- final org.osgi.framework.BundleContext firstContext = target
+ final BundleContext firstContext = target
.getContext();
// uninject
@@ -96,8 +118,23 @@
bundle.start();
assertTrue(target.hasContext());
- final org.osgi.framework.BundleContext secondContext = target
+ final BundleContext secondContext = target
.getContext();
assertNotSame(firstContext, secondContext);
}
+
+ public void testBundleInject() throws BundleException {
+ // inject
+ assertNotNull(target.getBundle());
+
+ // Contrary to the BC, the Bundle is available even for RESOLVED bundles
+ bundle.stop();
+
+ // not null but resolved _and_ still usable
+ assertNotNull(target.getBundle());
+ assertTrue(target.getBundle().getState() == Bundle.RESOLVED);
+ assertNotNull(target.getBundle().getSymbolicName());
+
+ assertNull(target.getContext());
+ }
}
diff --git a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
index bfd00bd..a30dfc0 100644
--- a/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java
@@ -48,7 +48,7 @@
import org.eclipse.e4.core.internal.tests.di.InjectionResultLeakTest;
import org.eclipse.e4.core.internal.tests.di.InvokeTest;
import org.eclipse.e4.core.internal.tests.di.RecursiveObjectCreationTest;
-import org.eclipse.e4.core.internal.tests.di.extensions.InjectionBundleContextTest;
+import org.eclipse.e4.core.internal.tests.di.extensions.InjectionOSGiTest;
import org.eclipse.e4.core.internal.tests.di.extensions.InjectionEventTest;
import org.eclipse.e4.core.internal.tests.di.extensions.InjectionMixedSuppliersTest;
import org.eclipse.e4.core.internal.tests.di.extensions.InjectionPreferencesTest;
@@ -63,7 +63,7 @@
addTestSuite(InjectionPreferencesTest.class);
addTestSuite(InjectionMixedSuppliersTest.class);
addTestSuite(InjectionEventTest.class);
- addTestSuite(InjectionBundleContextTest.class);
+ addTestSuite(InjectionOSGiTest.class);
// DI
addTestSuite(InjectionOrderTest.class);