summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Alexander Kuppe2013-12-05 03:23:10 (EST)
committer Gerrit Code Review @ Eclipse.org2013-12-18 13:56:03 (EST)
commit5131597f77f28f1bc65df79ea05c53160deb8e0a (patch)
tree151ccd828656fa93585e261d48f96f55e6ef4fda
parent0b55873052be3d9242cd59c10d7e89ce34c2a8dc (diff)
downloadeclipse.platform.runtime-5131597f77f28f1bc65df79ea05c53160deb8e0a.zip
eclipse.platform.runtime-5131597f77f28f1bc65df79ea05c53160deb8e0a.tar.gz
eclipse.platform.runtime-5131597f77f28f1bc65df79ea05c53160deb8e0a.tar.bz2
Bug 423212: Allow to inject OSGi BundleContext refs/changes/42/19342/6
Change-Id: Id4c340d88ba55c40e6936c18fa6d1970657ac33a Signed-off-by: Markus Alexander Kuppe <bugs.eclipse.org@lemmster.de>
-rw-r--r--bundles/org.eclipse.e4.core.di.extensions/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/bundleContext.xml8
-rw-r--r--bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/BundleContext.java28
-rw-r--r--bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/BundleContextObjectSupplier.java84
-rw-r--r--tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionBundleContextTest.java103
-rw-r--r--tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/tests/CoreTestSuite.java2
6 files changed, 227 insertions, 1 deletions
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 3eb44a5..d2a904b 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
@@ -13,7 +13,8 @@ Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: javax.annotation;version="1.0.0",
javax.inject;version="1.0.0"
-Service-Component: OSGI-INF/preferences.xml, OSGI-INF/events.xml
+Service-Component: OSGI-INF/preferences.xml, OSGI-INF/events.xml,
+ OSGI-INF/bundleContext.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/bundleContext.xml
new file mode 100644
index 0000000..a03d46c
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.di.extensions/OSGI-INF/bundleContext.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.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"/>
+ <service>
+ <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+ </service>
+</scr:component>
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/BundleContext.java
new file mode 100644
index 0000000..bf35865
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/extensions/BundleContext.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Markus Alexander Kuppe 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:
+ * Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.di.extensions;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.inject.Qualifier;
+
+/**
+ * https://bugs.eclipse.org/423212
+ */
+@Qualifier
+@Documented
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BundleContext {
+ // 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/BundleContextObjectSupplier.java
new file mode 100644
index 0000000..f2547e4
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.di.extensions/src/org/eclipse/e4/core/di/internal/extensions/BundleContextObjectSupplier.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Markus Alexander Kuppe 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:
+ * Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.di.internal.extensions;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.e4.core.di.InjectionException;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
+import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
+import org.eclipse.e4.core.di.suppliers.IRequestor;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.SynchronousBundleListener;
+
+public class BundleContextObjectSupplier 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();
+
+ @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);
+ }
+ } 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;
+ }
+ throw new InjectionException("Unable to inject BundleContext: " + bundle.getSymbolicName() + " bundle is not active or starting/stopping"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private void untrack(final IRequestor requestor) {
+ synchronized (requestor2listener) {
+ BundleListener l = requestor2listener.remove(requestor);
+ localBundleContext.removeBundleListener(l);
+ }
+ }
+
+ private void track(final Bundle bundle, final IRequestor requestor) {
+ // A _synchronous_ BundleListener asserts that the BC is un-injected,
+ // _before_ it becomes invalid (state-wise).
+ BundleListener listener = new SynchronousBundleListener() {
+ public void bundleChanged(BundleEvent event) {
+ if (event.getBundle().equals(bundle)) {
+ if (requestor.isValid()) {
+ requestor.resolveArguments(false);
+ requestor.execute();
+ }
+ }
+ }
+ };
+ synchronized (requestor2listener) {
+ localBundleContext.addBundleListener(listener);
+ requestor2listener.put(requestor, listener);
+ }
+ }
+}
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/InjectionBundleContextTest.java
new file mode 100644
index 0000000..9a09a21
--- /dev/null
+++ b/tests/org.eclipse.e4.core.tests/src/org/eclipse/e4/core/internal/tests/di/extensions/InjectionBundleContextTest.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Markus Alexander Kuppe 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:
+ * Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.internal.tests.di.extensions;
+
+import javax.inject.Inject;
+
+import junit.framework.TestCase;
+
+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.BundleContext;
+import org.eclipse.e4.core.internal.tests.CoreTestsActivator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+public class InjectionBundleContextTest extends TestCase {
+
+ // classed used as a user of the @BundleContext annotation
+ static class InjectionTarget {
+
+ private org.osgi.framework.BundleContext ctx;
+
+ @Inject
+ public void setBundleContext(
+ @BundleContext @Optional org.osgi.framework.BundleContext ctx) {
+ this.ctx = ctx;
+ }
+
+ public boolean hasContext() {
+ return this.ctx != null;
+ }
+
+ public org.osgi.framework.BundleContext getContext() {
+ return this.ctx;
+ }
+ }
+
+ private InjectionTarget target;
+ private Bundle bundle;
+
+ @Override
+ protected void tearDown() throws Exception {
+ bundle.start();
+
+ final org.osgi.framework.BundleContext bundleContext = CoreTestsActivator
+ .getDefault().getBundleContext();
+ final IEclipseContext localContext = EclipseContextFactory
+ .getServiceContext(bundleContext);
+
+ ContextInjectionFactory.uninject(target, localContext);
+
+ super.tearDown();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final org.osgi.framework.BundleContext bundleContext = CoreTestsActivator
+ .getDefault().getBundleContext();
+ bundle = bundleContext.getBundle();
+
+ final IEclipseContext localContext = EclipseContextFactory
+ .getServiceContext(bundleContext);
+
+ target = ContextInjectionFactory.make(InjectionTarget.class,
+ localContext);
+ }
+
+ public void testInject() {
+ assertTrue(target.hasContext());
+ }
+
+ public void testUnInject() throws BundleException, InterruptedException {
+ // inject
+ assertTrue(target.hasContext());
+
+ // Check also that the BundleContext instance has indeed changed
+ final org.osgi.framework.BundleContext firstContext = target
+ .getContext();
+
+ // uninject
+ bundle.stop();
+ assertFalse(target.hasContext());
+
+ // re-inject
+ bundle.start();
+ assertTrue(target.hasContext());
+
+ final org.osgi.framework.BundleContext secondContext = target
+ .getContext();
+ assertNotSame(firstContext, secondContext);
+ }
+}
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 dcf7f06..bfd00bd 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,6 +48,7 @@ import org.eclipse.e4.core.internal.tests.di.InjectionOrderTest;
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.InjectionEventTest;
import org.eclipse.e4.core.internal.tests.di.extensions.InjectionMixedSuppliersTest;
import org.eclipse.e4.core.internal.tests.di.extensions.InjectionPreferencesTest;
@@ -62,6 +63,7 @@ public class CoreTestSuite extends TestSuite {
addTestSuite(InjectionPreferencesTest.class);
addTestSuite(InjectionMixedSuppliersTest.class);
addTestSuite(InjectionEventTest.class);
+ addTestSuite(InjectionBundleContextTest.class);
// DI
addTestSuite(InjectionOrderTest.class);