Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: cde905cae5fde80b7241e9c7e47e0eb5e492c690 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*******************************************************************************
 * 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.lang.reflect.Type;
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 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(OSGiObjectSupplier.class).getBundleContext();

	@Override
	public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
		final Class<?> requestingObjectClass = requestor.getRequestingObjectClass();

		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);
			}

			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);
		}
		// Annotation used with unsupported type
		return null;
	}

	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);
		}
	}
}

Back to the top