Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: d441e3a0eade705817446fa550a9995db46d0338 (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*******************************************************************************
 * Copyright (c) 2008, 2013 VMware Inc.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   VMware Inc. - initial contribution
 *******************************************************************************/

package org.eclipse.equinox.internal.region;

import java.io.*;
import java.util.*;
import org.eclipse.equinox.internal.region.management.StandardManageableRegionDigraph;
import org.eclipse.equinox.region.Region;
import org.eclipse.equinox.region.RegionDigraph;
import org.osgi.framework.*;
import org.osgi.framework.hooks.bundle.*;
import org.osgi.framework.hooks.resolver.ResolverHookFactory;

/**
 * Creates and manages the {@link RegionDigraph} associated
 * with the running framework.
 * <p />
 * 
 * <strong>Concurrent Semantics</strong><br />
 * 
 * Threadsafe.
 * 
 */
public final class RegionManager implements BundleActivator {

	private static final String REGION_KERNEL = "org.eclipse.equinox.region.kernel"; //$NON-NLS-1$
	private static final String REGION_DOMAIN_PROP = "org.eclipse.equinox.region.domain"; //$NON-NLS-1$
	private static final String DIGRAPH_FILE = "digraph"; //$NON-NLS-1$
	private static final String REGION_REGISTER_MBEANS = "org.eclipse.equinox.region.register.mbeans"; //$NON-NLS-1$
	private static final Dictionary<String, Object> MAX_RANKING = new Hashtable<String, Object>(Collections.singletonMap(Constants.SERVICE_RANKING, Integer.MAX_VALUE));

	Collection<ServiceRegistration<?>> registrations = new ArrayList<ServiceRegistration<?>>();

	private BundleContext bundleContext;

	private final ThreadLocal<Region> threadLocal = new ThreadLocal<Region>();

	private String domain;

	private StandardRegionDigraph digraph;

	private StandardManageableRegionDigraph digraphMBean;

	public void start(BundleContext bc) throws BundleException, IOException, InvalidSyntaxException {
		this.bundleContext = bc;
		this.domain = bc.getProperty(REGION_DOMAIN_PROP);
		if (this.domain == null)
			this.domain = REGION_DOMAIN_PROP;
		digraph = loadRegionDigraph();
		registerRegionHooks(digraph);
		// after registering the region hooks we need to verify no ophans exist
		// if they do then we assume the need to be in the kernel region
		checkForOrphans(digraph);
		digraphMBean = registerDigraphMbean(digraph);
		registerService(RegionDigraph.class, digraph);
	}

	private void checkForOrphans(StandardRegionDigraph regionDigraph) {
		// we assume the system bundle is in the root region.
		Region rootRegion = regionDigraph.getRegion(0);
		if (rootRegion != null) {
			Bundle[] bundles = bundleContext.getBundles();
			for (Bundle bundle : bundles) {
				if (regionDigraph.getRegion(bundle) == null) {
					// we have an orphan; add it to the root region
					try {
						rootRegion.addBundle(bundle.getBundleId());
					} catch (BundleException e) {
						// ignore, someone added the bundle to another region since we checked
					}
				}
			}
		}
	}

	public void stop(BundleContext bc) throws IOException {
		if (digraphMBean != null) {
			digraphMBean.unregisterMbean();
			digraphMBean = null;
		}
		for (ServiceRegistration<?> registration : registrations)
			registration.unregister();
		saveDigraph();
	}

	private StandardRegionDigraph loadRegionDigraph() throws BundleException, IOException, InvalidSyntaxException {
		File digraphFile = bundleContext.getDataFile(DIGRAPH_FILE);
		if (digraphFile == null || !digraphFile.exists()) {
			// no persistent digraph available, create a new one
			return createRegionDigraph();
		}
		FileInputStream in = new FileInputStream(digraphFile);
		try {
			// TODO need to validate bundle IDs to make sure they are consistent with current bundles
			return StandardRegionDigraphPersistence.readRegionDigraph(new DataInputStream(in), this.bundleContext, this.threadLocal);
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				// We tried our best to clean up
			}
		}
	}

	private StandardRegionDigraph createRegionDigraph() throws BundleException {
		StandardRegionDigraph regionDigraph = new StandardRegionDigraph(this.bundleContext, this.threadLocal);
		Region kernelRegion = regionDigraph.createRegion(REGION_KERNEL);
		for (Bundle bundle : this.bundleContext.getBundles()) {
			kernelRegion.addBundle(bundle);
		}
		return regionDigraph;
	}

	private void saveDigraph() throws IOException {
		FileOutputStream digraphFile = new FileOutputStream(bundleContext.getDataFile(DIGRAPH_FILE));
		try {
			digraph.getRegionDigraphPersistence().save(digraph, digraphFile);
		} finally {
			try {
				digraphFile.close();
			} catch (IOException e) {
				// ignore;
			}
		}

	}

	private StandardManageableRegionDigraph registerDigraphMbean(RegionDigraph regionDigraph) {
		if ("false".equals(this.bundleContext.getProperty(REGION_REGISTER_MBEANS))) { //$NON-NLS-1$
			return null;
		}
		StandardManageableRegionDigraph standardManageableRegionDigraph = new StandardManageableRegionDigraph(regionDigraph, this.domain, this.bundleContext);
		standardManageableRegionDigraph.registerMBean();
		return standardManageableRegionDigraph;
	}

	@SuppressWarnings("deprecation")
	private void registerRegionHooks(StandardRegionDigraph regionDigraph) {
		registerService(ResolverHookFactory.class, regionDigraph.getResolverHookFactory());

		registerService(CollisionHook.class, regionDigraph.getBundleCollisionHook());
		registerService(FindHook.class, regionDigraph.getBundleFindHook());
		registerService(EventHook.class, regionDigraph.getBundleEventHook());

		registerService(org.osgi.framework.hooks.service.FindHook.class, regionDigraph.getServiceFindHook());
		registerService(org.osgi.framework.hooks.service.EventHook.class, regionDigraph.getServiceEventHook());
	}

	private <S> void registerService(Class<S> clazz, S service) {
		this.registrations.add(this.bundleContext.registerService(clazz, service, MAX_RANKING));
	}
}

Back to the top