Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 326011
Collapse All | Expand All

(-).settings/.api_filters (+7 lines)
Lines 791-796 Link Here
791
</message_arguments>
791
</message_arguments>
792
</filter>
792
</filter>
793
</resource>
793
</resource>
794
<resource path="osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java" type="org.osgi.framework.hooks.resolver.ResolverHookFactory">
795
<filter comment="Ignore OSGi API" id="1110441988">
796
<message_arguments>
797
<message_argument value="org.osgi.framework.hooks.resolver.ResolverHookFactory"/>
798
</message_arguments>
799
</filter>
800
</resource>
794
<resource path="osgi/src/org/osgi/framework/launch/Framework.java" type="org.osgi.framework.launch.Framework">
801
<resource path="osgi/src/org/osgi/framework/launch/Framework.java" type="org.osgi.framework.launch.Framework">
795
<filter id="403984517">
802
<filter id="403984517">
796
<message_arguments>
803
<message_arguments>
(-)core/adaptor/org/eclipse/osgi/service/resolver/State.java (-2 / +44 lines)
Lines 10-15 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.osgi.service.resolver;
11
package org.eclipse.osgi.service.resolver;
12
12
13
import java.util.Collection;
13
import java.util.Dictionary;
14
import java.util.Dictionary;
14
import org.osgi.framework.BundleException;
15
import org.osgi.framework.BundleException;
15
import org.osgi.framework.Version;
16
import org.osgi.framework.Version;
Lines 346-352 Link Here
346
347
347
	/**
348
	/**
348
	 * Resolves the constraints contained in this state using the resolver
349
	 * Resolves the constraints contained in this state using the resolver
349
	 * currently associated with the state in a incremental, "least-perturbing" 
350
	 * currently associated with the state in an incremental, "least-perturbing" 
350
	 * mode, and returns a delta describing the changes in resolved states and 
351
	 * mode, and returns a delta describing the changes in resolved states and 
351
	 * dependencies in the state.
352
	 * dependencies in the state.
352
	 * 
353
	 * 
Lines 359-372 Link Here
359
	public StateDelta resolve(BundleDescription[] discard);
360
	public StateDelta resolve(BundleDescription[] discard);
360
361
361
	/**
362
	/**
363
	 * Resolves the constraints contained in this state using the resolver
364
	 * currently associated with the state in an incremental, "least-perturbing"
365
	 * mode, and returns a delta describing the changes in resolved states and
366
	 * dependencies in the state.  If discard is set to true the 
367
	 * the descriptions contained in the resolve array will have their 
368
	 * current resolution state discarded and will be re-resolved.
369
	 * This method will attempt to resolve the supplied descriptions
370
	 * and may attempt to resolve any other unresolved descriptions contained
371
	 * in this state.
372
	 * 
373
	 * @param resolve an array containing descriptions for bundles to resolve.
374
	 * @param discard a value of true indicates the resolve descriptions
375
	 * should have their current resolution state discarded and re-resolved.
376
	 * @return a delta describing the changes in the resolved state and
377
	 * interconnections.
378
	 * @since 3.7
379
	 */
380
	public StateDelta resolve(BundleDescription[] resolve, boolean discard);
381
382
	/**
362
	 * Sets the version overrides which are to be applied during the resolutoin
383
	 * Sets the version overrides which are to be applied during the resolutoin
363
	 * of this state. Version overrides allow external forces to
384
	 * of this state. Version overrides allow external forces to
364
	 * refine/override the version constraints setup by the components in the
385
	 * refine/override the version constraints setup by the components in the
365
	 * state.
386
	 * state.
366
	 * 
387
	 * 
367
	 * @param value
388
	 * @param value
389
	 * @deprecated The exact form of this has never been defined.  There is
390
	 * no alternative method available.
368
	 */
391
	 */
369
	// TODO the exact form of this is not defined as yet.
370
	public void setOverrides(Object value);
392
	public void setOverrides(Object value);
371
393
372
	/**
394
	/**
Lines 385-390 Link Here
385
	public BundleDescription[] getRemovalPending();
407
	public BundleDescription[] getRemovalPending();
386
408
387
	/**
409
	/**
410
	 * Returns the dependency closure for the specified bundles.
411
	 * 
412
	 * <p>
413
	 * A graph of bundles is computed starting with the specified bundles. The
414
	 * graph is expanded by adding any bundle that is either wired to a package
415
	 * that is currently exported by a bundle in the graph or requires a bundle
416
	 * in the graph. The graph is fully constructed when there is no bundle
417
	 * outside the graph that is wired to a bundle in the graph. The graph may
418
	 * contain removal pending bundles.
419
	 * 
420
	 * @param bundles The initial bundles for which to generate the dependency
421
	 *        closure.
422
	 * @return A collection containing a snapshot of the dependency closure of
423
	 *         the specified bundles, or an empty collection if there were no
424
	 *         specified bundles.
425
	 * @since 3.7
426
	 */
427
	public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles);
428
429
	/**
388
	 * Returns whether this state is empty.
430
	 * Returns whether this state is empty.
389
	 * @return <code>true</code> if this state is empty, <code>false</code> 
431
	 * @return <code>true</code> if this state is empty, <code>false</code> 
390
	 * 	otherwise
432
	 * 	otherwise
(-)core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHook.java (-178 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.osgi.framework.internal.core;
12
13
import java.util.*;
14
import org.eclipse.osgi.framework.debug.Debug;
15
import org.eclipse.osgi.internal.serviceregistry.*;
16
import org.eclipse.osgi.util.NLS;
17
import org.osgi.framework.*;
18
import org.osgi.framework.hooks.resolver.ResolverHook;
19
import org.osgi.framework.wiring.BundleRevision;
20
import org.osgi.framework.wiring.Capability;
21
22
/**
23
 * This class encapsulates the delegation to ResolverHooks that are registered with the service
24
 * registry.  This way the resolver implementation only has to call out to a single hook
25
 * which does all the necessary service registry lookups.
26
 * 
27
 * This class is not thread safe and expects external synchronization.
28
 *
29
 */
30
public class CoreResolverHook implements ResolverHook {
31
	// need a tuple to hold the service reference and hook object
32
	// do not use a map for performance reasons; no need to hash based on a key.
33
	static class HookReference {
34
		public HookReference(ServiceReferenceImpl<ResolverHook> reference, ResolverHook hook) {
35
			this.reference = reference;
36
			this.hook = hook;
37
		}
38
39
		final ServiceReferenceImpl<ResolverHook> reference;
40
		final ResolverHook hook;
41
	}
42
43
	private final BundleContextImpl context;
44
	private final ServiceRegistry registry;
45
	private final List<HookReference> hooks = new ArrayList<HookReference>(0);
46
47
	public CoreResolverHook(BundleContextImpl context, ServiceRegistry registry) {
48
		this.context = context;
49
		this.registry = registry;
50
	}
51
52
	private void handleHookException(Throwable t, ResolverHook hook, String method, Bundle hookBundle) {
53
		if (Debug.DEBUG_HOOKS) {
54
			Debug.println(hook.getClass().getName() + "." + method + "() exception: " + t.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
55
			Debug.printStackTrace(t);
56
		}
57
		// allow the adaptor to handle this unexpected error
58
		context.framework.getAdaptor().handleRuntimeError(t);
59
		ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, hook.getClass().getName(), method), t);
60
		context.framework.publishFrameworkEvent(FrameworkEvent.ERROR, hookBundle, se);
61
	}
62
63
	private ServiceReferenceImpl<ResolverHook>[] getHookReferences() {
64
		try {
65
			@SuppressWarnings("unchecked")
66
			ServiceReferenceImpl<ResolverHook>[] result = (ServiceReferenceImpl<ResolverHook>[]) registry.getServiceReferences(context, ResolverHook.class.getName(), null, false, false);
67
			return result;
68
		} catch (InvalidSyntaxException e) {
69
			// cannot happen; no filter
70
			return null;
71
		}
72
	}
73
74
	public void begin() {
75
		if (Debug.DEBUG_HOOKS) {
76
			Debug.println("ResolverHook.begin"); //$NON-NLS-1$
77
		}
78
		ServiceReferenceImpl<ResolverHook>[] refs = getHookReferences();
79
		if (refs == null || refs.length == 0)
80
			return;
81
		for (ServiceReferenceImpl<ResolverHook> hookRef : refs) {
82
			ResolverHook hook = context.getService(hookRef);
83
			if (hook != null) {
84
				hooks.add(new HookReference(hookRef, hook));
85
				try {
86
					hook.begin();
87
				} catch (Throwable t) {
88
					handleHookException(t, hook, "begin", hookRef.getBundle()); //$NON-NLS-1$
89
				}
90
			}
91
		}
92
	}
93
94
	public void filterResolvable(Collection<BundleRevision> candidates) {
95
		if (Debug.DEBUG_HOOKS) {
96
			Debug.println("ResolverHook.filterResolvable(" + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$
97
		}
98
		if (hooks.isEmpty())
99
			return;
100
		candidates = new ShrinkableCollection<BundleRevision>(candidates);
101
		for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
102
			HookReference hookRef = iHooks.next();
103
			if (hookRef.reference.getBundle() == null) {
104
				iHooks.remove();
105
			} else {
106
				try {
107
					hookRef.hook.filterResolvable(candidates);
108
				} catch (Throwable t) {
109
					handleHookException(t, hookRef.hook, "filterResolvable", hookRef.reference.getBundle()); //$NON-NLS-1$
110
				}
111
			}
112
		}
113
	}
114
115
	public void filterSingletonCollisions(Capability singleton, Collection<Capability> collisionCandidates) {
116
		if (Debug.DEBUG_HOOKS) {
117
			Debug.println("ResolverHook.filterSingletonCollisions(" + singleton + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
118
		}
119
		if (hooks.isEmpty())
120
			return;
121
		collisionCandidates = new ShrinkableCollection<Capability>(collisionCandidates);
122
		for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
123
			HookReference hookRef = iHooks.next();
124
			if (hookRef.reference.getBundle() == null) {
125
				iHooks.remove();
126
			} else {
127
				try {
128
					hookRef.hook.filterSingletonCollisions(singleton, collisionCandidates);
129
				} catch (Throwable t) {
130
					handleHookException(t, hookRef.hook, "filterSingletonCollisions", hookRef.reference.getBundle()); //$NON-NLS-1$
131
				}
132
			}
133
		}
134
	}
135
136
	public void filterMatches(BundleRevision requirer, Collection<Capability> candidates) {
137
		if (Debug.DEBUG_HOOKS) {
138
			Debug.println("ResolverHook.filterMatches(" + requirer + ", " + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
139
		}
140
		if (hooks.isEmpty())
141
			return;
142
		candidates = new ShrinkableCollection<Capability>(candidates);
143
		for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
144
			HookReference hookRef = iHooks.next();
145
			if (hookRef.reference.getBundle() == null) {
146
				iHooks.remove();
147
			} else {
148
				try {
149
					hookRef.hook.filterMatches(requirer, candidates);
150
				} catch (Throwable t) {
151
					handleHookException(t, hookRef.hook, "filterMatches", hookRef.reference.getBundle()); //$NON-NLS-1$
152
				}
153
			}
154
		}
155
	}
156
157
	public void end() {
158
		if (Debug.DEBUG_HOOKS) {
159
			Debug.println("ResolverHook.end"); //$NON-NLS-1$
160
		}
161
		if (hooks.isEmpty())
162
			return;
163
		for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
164
			HookReference hookRef = iHooks.next();
165
			// We do not remove unregistered services here because we are going to remove of of them at the end
166
			if (hookRef.reference.getBundle() != null) {
167
				try {
168
					hookRef.hook.end();
169
				} catch (Throwable t) {
170
					handleHookException(t, hookRef.hook, "end", hookRef.reference.getBundle()); //$NON-NLS-1$
171
				}
172
				context.ungetService(hookRef.reference);
173
			}
174
		}
175
		hooks.clear();
176
	}
177
178
}
(-)core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHookFactory.java (+188 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.osgi.framework.internal.core;
12
13
import java.util.*;
14
import org.eclipse.osgi.framework.debug.Debug;
15
import org.eclipse.osgi.internal.serviceregistry.*;
16
import org.eclipse.osgi.util.NLS;
17
import org.osgi.framework.*;
18
import org.osgi.framework.hooks.resolver.ResolverHook;
19
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
20
import org.osgi.framework.wiring.BundleRevision;
21
import org.osgi.framework.wiring.Capability;
22
23
/**
24
 * This class encapsulates the delegation to ResolverHooks that are registered with the service
25
 * registry.  This way the resolver implementation only has to call out to a single hook
26
 * which does all the necessary service registry lookups.
27
 * 
28
 * This class is not thread safe and expects external synchronization.
29
 *
30
 */
31
public class CoreResolverHookFactory implements ResolverHookFactory {
32
	// need a tuple to hold the service reference and hook object
33
	// do not use a map for performance reasons; no need to hash based on a key.
34
	static class HookReference {
35
		public HookReference(ServiceReferenceImpl<ResolverHookFactory> reference, ResolverHook hook) {
36
			this.reference = reference;
37
			this.hook = hook;
38
		}
39
40
		final ServiceReferenceImpl<ResolverHookFactory> reference;
41
		final ResolverHook hook;
42
	}
43
44
	private final BundleContextImpl context;
45
	private final ServiceRegistry registry;
46
47
	public CoreResolverHookFactory(BundleContextImpl context, ServiceRegistry registry) {
48
		this.context = context;
49
		this.registry = registry;
50
	}
51
52
	void handleHookException(Throwable t, Object hook, String method, Bundle hookBundle) {
53
		if (Debug.DEBUG_HOOKS) {
54
			Debug.println(hook.getClass().getName() + "." + method + "() exception: " + t.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
55
			Debug.printStackTrace(t);
56
		}
57
		// allow the adaptor to handle this unexpected error
58
		context.framework.getAdaptor().handleRuntimeError(t);
59
		ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, hook.getClass().getName(), method), t);
60
		context.framework.publishFrameworkEvent(FrameworkEvent.ERROR, hookBundle, se);
61
	}
62
63
	private ServiceReferenceImpl<ResolverHookFactory>[] getHookReferences() {
64
		try {
65
			@SuppressWarnings("unchecked")
66
			ServiceReferenceImpl<ResolverHookFactory>[] result = (ServiceReferenceImpl<ResolverHookFactory>[]) registry.getServiceReferences(context, ResolverHookFactory.class.getName(), null, false, false);
67
			return result;
68
		} catch (InvalidSyntaxException e) {
69
			// cannot happen; no filter
70
			return null;
71
		}
72
	}
73
74
	public ResolverHook begin(Collection<BundleRevision> triggers) {
75
		if (Debug.DEBUG_HOOKS) {
76
			Debug.println("ResolverHook.begin"); //$NON-NLS-1$
77
		}
78
		ServiceReferenceImpl<ResolverHookFactory>[] refs = getHookReferences();
79
		@SuppressWarnings("unchecked")
80
		List<HookReference> hookRefs = refs == null ? Collections.EMPTY_LIST : new ArrayList<CoreResolverHookFactory.HookReference>(refs.length);
81
		if (refs != null)
82
			for (ServiceReferenceImpl<ResolverHookFactory> hookRef : refs) {
83
				ResolverHookFactory factory = context.getService(hookRef);
84
				if (factory != null) {
85
					try {
86
						ResolverHook hook = factory.begin(triggers);
87
						if (hook != null)
88
							hookRefs.add(new HookReference(hookRef, hook));
89
					} catch (Throwable t) {
90
						handleHookException(t, factory, "begin", hookRef.getBundle()); //$NON-NLS-1$
91
					}
92
				}
93
			}
94
		return new CoreResolverHook(hookRefs);
95
	}
96
97
	class CoreResolverHook implements ResolverHook {
98
		private final List<HookReference> hooks;
99
100
		CoreResolverHook(List<HookReference> hooks) {
101
			this.hooks = hooks;
102
		}
103
104
		public void filterResolvable(Collection<BundleRevision> candidates) {
105
			if (Debug.DEBUG_HOOKS) {
106
				Debug.println("ResolverHook.filterResolvable(" + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$
107
			}
108
			if (hooks.isEmpty())
109
				return;
110
			candidates = new ShrinkableCollection<BundleRevision>(candidates);
111
			for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
112
				HookReference hookRef = iHooks.next();
113
				if (hookRef.reference.getBundle() == null) {
114
					iHooks.remove();
115
				} else {
116
					try {
117
						hookRef.hook.filterResolvable(candidates);
118
					} catch (Throwable t) {
119
						handleHookException(t, hookRef.hook, "filterResolvable", hookRef.reference.getBundle()); //$NON-NLS-1$
120
					}
121
				}
122
			}
123
		}
124
125
		public void filterSingletonCollisions(Capability singleton, Collection<Capability> collisionCandidates) {
126
			if (Debug.DEBUG_HOOKS) {
127
				Debug.println("ResolverHook.filterSingletonCollisions(" + singleton + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
128
			}
129
			if (hooks.isEmpty())
130
				return;
131
			collisionCandidates = new ShrinkableCollection<Capability>(collisionCandidates);
132
			for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
133
				HookReference hookRef = iHooks.next();
134
				if (hookRef.reference.getBundle() == null) {
135
					iHooks.remove();
136
				} else {
137
					try {
138
						hookRef.hook.filterSingletonCollisions(singleton, collisionCandidates);
139
					} catch (Throwable t) {
140
						handleHookException(t, hookRef.hook, "filterSingletonCollisions", hookRef.reference.getBundle()); //$NON-NLS-1$
141
					}
142
				}
143
			}
144
		}
145
146
		public void filterMatches(BundleRevision requirer, Collection<Capability> candidates) {
147
			if (Debug.DEBUG_HOOKS) {
148
				Debug.println("ResolverHook.filterMatches(" + requirer + ", " + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
149
			}
150
			if (hooks.isEmpty())
151
				return;
152
			candidates = new ShrinkableCollection<Capability>(candidates);
153
			for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
154
				HookReference hookRef = iHooks.next();
155
				if (hookRef.reference.getBundle() == null) {
156
					iHooks.remove();
157
				} else {
158
					try {
159
						hookRef.hook.filterMatches(requirer, candidates);
160
					} catch (Throwable t) {
161
						handleHookException(t, hookRef.hook, "filterMatches", hookRef.reference.getBundle()); //$NON-NLS-1$
162
					}
163
				}
164
			}
165
		}
166
167
		public void end() {
168
			if (Debug.DEBUG_HOOKS) {
169
				Debug.println("ResolverHook.end"); //$NON-NLS-1$
170
			}
171
			if (hooks.isEmpty())
172
				return;
173
			for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) {
174
				HookReference hookRef = iHooks.next();
175
				// We do not remove unregistered services here because we are going to remove of of them at the end
176
				if (hookRef.reference.getBundle() != null) {
177
					try {
178
						hookRef.hook.end();
179
					} catch (Throwable t) {
180
						handleHookException(t, hookRef.hook, "end", hookRef.reference.getBundle()); //$NON-NLS-1$
181
					}
182
					context.ungetService(hookRef.reference);
183
				}
184
			}
185
			hooks.clear();
186
		}
187
	}
188
}
(-)core/framework/org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java (-36 / +30 lines)
Lines 182-190 Link Here
182
182
183
	public boolean resolveBundles(Bundle[] bundles) {
183
	public boolean resolveBundles(Bundle[] bundles) {
184
		framework.checkAdminPermission(framework.systemBundle, AdminPermission.RESOLVE);
184
		framework.checkAdminPermission(framework.systemBundle, AdminPermission.RESOLVE);
185
		doResolveBundles(null, false, null);
186
		if (bundles == null)
185
		if (bundles == null)
187
			bundles = framework.getAllBundles();
186
			bundles = framework.getAllBundles();
187
		doResolveBundles(bundles, false, null);
188
		for (int i = 0; i < bundles.length; i++)
188
		for (int i = 0; i < bundles.length; i++)
189
			if (!((AbstractBundle) bundles[i]).isResolved())
189
			if (!((AbstractBundle) bundles[i]).isResolved())
190
				return false;
190
				return false;
Lines 193-199 Link Here
193
	}
193
	}
194
194
195
	// This method is protected to enable a work around to bug 245251
195
	// This method is protected to enable a work around to bug 245251
196
	synchronized protected void doResolveBundles(AbstractBundle[] bundles, boolean refreshPackages, FrameworkListener[] listeners) {
196
	synchronized protected void doResolveBundles(Bundle[] bundles, boolean refreshPackages, FrameworkListener[] listeners) {
197
		try {
197
		try {
198
			if (Profile.PROFILE && Profile.STARTUP)
198
			if (Profile.PROFILE && Profile.STARTUP)
199
				Profile.logEnter("resolve bundles"); //$NON-NLS-1$
199
				Profile.logEnter("resolve bundles"); //$NON-NLS-1$
Lines 201-212 Link Here
201
			State systemState = framework.adaptor.getState();
201
			State systemState = framework.adaptor.getState();
202
			BundleDescription[] descriptions = null;
202
			BundleDescription[] descriptions = null;
203
			int numBundles = bundles == null ? 0 : bundles.length;
203
			int numBundles = bundles == null ? 0 : bundles.length;
204
			if (!refreshPackages)
204
			if (!refreshPackages) {
205
				// in this case we must make descriptions non-null so we do
205
				List<BundleDescription> resolving = new ArrayList<BundleDescription>();
206
				// not force the removal pendings to be processed when resolving
206
				for (Bundle bundle : bundles) {
207
				// the state.
207
					BundleDescription description = ((AbstractBundle) bundle).getBundleDescription();
208
				descriptions = new BundleDescription[0];
208
					if (((bundle.getState() & Bundle.UNINSTALLED) == 0) && description != null)
209
			else if (numBundles > 0) {
209
						resolving.add(description);
210
				}
211
				descriptions = resolving.toArray(new BundleDescription[resolving.size()]);
212
			} else if (numBundles > 0) {
210
				// populate the resolved hosts package sources first (do this outside sync block: bug 280929)
213
				// populate the resolved hosts package sources first (do this outside sync block: bug 280929)
211
				populateLoaders(framework.getAllBundles());
214
				populateLoaders(framework.getAllBundles());
212
				synchronized (framework.bundles) {
215
				synchronized (framework.bundles) {
Lines 214-220 Link Here
214
					List<BundleDescription> results = new ArrayList<BundleDescription>(numBundles);
217
					List<BundleDescription> results = new ArrayList<BundleDescription>(numBundles);
215
					BundleDelta[] addDeltas = null;
218
					BundleDelta[] addDeltas = null;
216
					for (int i = 0; i < numBundles; i++) {
219
					for (int i = 0; i < numBundles; i++) {
217
						BundleDescription description = bundles[i].getBundleDescription();
220
						BundleDescription description = ((AbstractBundle) bundles[i]).getBundleDescription();
218
						if (description != null && description.getBundleId() != 0 && !results.contains(description))
221
						if (description != null && description.getBundleId() != 0 && !results.contains(description))
219
							results.add(description);
222
							results.add(description);
220
						// add in any bundles that have the same symbolic name see bug (169593)
223
						// add in any bundles that have the same symbolic name see bug (169593)
Lines 235-241 Link Here
235
					descriptions = (results.size() == 0 ? null : results.toArray(new BundleDescription[results.size()]));
238
					descriptions = (results.size() == 0 ? null : results.toArray(new BundleDescription[results.size()]));
236
				}
239
				}
237
			}
240
			}
238
			BundleDelta[] delta = systemState.resolve(descriptions).getChanges();
241
			BundleDelta[] delta = systemState.resolve(descriptions, refreshPackages).getChanges();
239
			processDelta(delta, refreshPackages, systemState);
242
			processDelta(delta, refreshPackages, systemState);
240
		} catch (Throwable t) {
243
		} catch (Throwable t) {
241
			if (Debug.DEBUG_PACKAGEADMIN) {
244
			if (Debug.DEBUG_PACKAGEADMIN) {
Lines 743-749 Link Here
743
		// We currently have three places this is kept (PackageAdminImpl, StateImpl and ResolverImpl)
746
		// We currently have three places this is kept (PackageAdminImpl, StateImpl and ResolverImpl)
744
		// Using the state's because it has easy access to the uninstalled Bundle objects
747
		// Using the state's because it has easy access to the uninstalled Bundle objects
745
		BundleDescription[] removals = framework.adaptor.getState().getRemovalPending();
748
		BundleDescription[] removals = framework.adaptor.getState().getRemovalPending();
746
		Collection<Bundle> result = new HashSet<Bundle>();
749
		Set<Bundle> result = new HashSet<Bundle>();
747
		for (int i = 0; i < removals.length; i++) {
750
		for (int i = 0; i < removals.length; i++) {
748
			Object ref = removals[i].getUserObject();
751
			Object ref = removals[i].getUserObject();
749
			if (ref instanceof BundleReference)
752
			if (ref instanceof BundleReference)
Lines 753-789 Link Here
753
	}
756
	}
754
757
755
	public Collection<Bundle> getDependencyClosure(Collection<Bundle> bundles) {
758
	public Collection<Bundle> getDependencyClosure(Collection<Bundle> bundles) {
756
		State state = framework.adaptor.getState();
759
		Collection<BundleDescription> descriptions = getDescriptionClosure(bundles);
757
		BundleDescription[] removals = state.getRemovalPending();
758
		Set<Bundle> result = new HashSet<Bundle>();
760
		Set<Bundle> result = new HashSet<Bundle>();
759
		for (Bundle bundle : bundles) {
761
		for (BundleDescription description : descriptions) {
760
			addDependents(bundle, result, removals, state);
762
			Object userObject = description.getUserObject();
763
			if (userObject instanceof BundleReference) {
764
				Bundle bundle = ((BundleReference) userObject).getBundle();
765
				if (bundle != null)
766
					result.add(bundle);
767
			}
761
		}
768
		}
762
		return result;
769
		return result;
763
	}
770
	}
764
771
765
	private static void addDependents(Bundle bundle, Set<Bundle> result, BundleDescription[] removals, State state) {
772
	private Collection<BundleDescription> getDescriptionClosure(Collection<Bundle> bundles) {
766
		if (result.contains(bundle))
773
		State state = framework.adaptor.getState();
767
			return; // avoid cycles
774
		Collection<BundleDescription> descriptions = new ArrayList<BundleDescription>();
768
		result.add(bundle);
775
		for (Bundle bundle : bundles) {
769
		BundleDescription description = state.getBundle(bundle.getBundleId());
776
			BundleDescription description = state.getBundle(bundle.getBundleId());
770
		addDependents(description, result, removals, state);
777
			if (description != null)
771
		// check if this is a removal pending
778
				descriptions.add(description);
772
		for (BundleDescription removed : removals) {
773
			if (removed.getBundleId() == bundle.getBundleId())
774
				addDependents(removed, result, removals, state);
775
		}
779
		}
776
780
		return state.getDependencyClosure(descriptions);
777
	}
781
	}
778
782
779
	private static void addDependents(BundleDescription description, Set<Bundle> result, BundleDescription[] removals, State state) {
780
		if (description == null)
781
			return;
782
		BundleDescription[] dependents = description.getDependents();
783
		for (BundleDescription dependent : dependents) {
784
			Object ref = dependent.getUserObject();
785
			if (ref instanceof BundleReference)
786
				addDependents(((BundleReference) ref).getBundle(), result, removals, state);
787
		}
788
	}
789
}
783
}
(-)core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java (-1 / +1 lines)
Lines 60-66 Link Here
60
		framework.adaptor.frameworkStart(bc);
60
		framework.adaptor.frameworkStart(bc);
61
		State state = framework.adaptor.getState();
61
		State state = framework.adaptor.getState();
62
		if (state instanceof StateImpl)
62
		if (state instanceof StateImpl)
63
			((StateImpl) state).setResolverHook(new CoreResolverHook((BundleContextImpl) context, framework.getServiceRegistry()));
63
			((StateImpl) state).setResolverHookFactory(new CoreResolverHookFactory((BundleContextImpl) context, framework.getServiceRegistry()));
64
		// attempt to resolve all bundles
64
		// attempt to resolve all bundles
65
		// this is done after the adaptor.frameworkStart has been called
65
		// this is done after the adaptor.frameworkStart has been called
66
		// this should be the first time the resolver State is accessed
66
		// this should be the first time the resolver State is accessed
(-)osgi/src/org/osgi/framework/CapabilityPermission.java (-311 / +174 lines)
Lines 33-39 Link Here
33
import java.util.Enumeration;
33
import java.util.Enumeration;
34
import java.util.HashMap;
34
import java.util.HashMap;
35
import java.util.HashSet;
35
import java.util.HashSet;
36
import java.util.Hashtable;
37
import java.util.List;
36
import java.util.List;
38
import java.util.Map;
37
import java.util.Map;
39
import java.util.Set;
38
import java.util.Set;
Lines 48-59 Link Here
48
 * </ul>
47
 * </ul>
49
 * 
48
 * 
50
 * @ThreadSafe
49
 * @ThreadSafe
51
 * @version $Id: 11e47883a0c36de7cd69d0436287d41f8bd30f17 $
50
 * @version $Id: 4017ce21a422bbf0d4a9d0f192104eced96bec30 $
52
 * @since 1.6
51
 * @since 1.6
53
 */
52
 */
54
53
55
public final class CapabilityPermission extends BasicPermission {
54
public final class CapabilityPermission extends BasicPermission {
56
	static final long			serialVersionUID	= -7662148639076511574L;
55
	static final long								serialVersionUID	= -7662148639076511574L;
57
	/**
56
	/**
58
	 * The action string {@code require}.
57
	 * The action string {@code require}.
59
	 */
58
	 */
Lines 63-123 Link Here
63
	 */
62
	 */
64
	public final static String						PROVIDE				= "provide";
63
	public final static String						PROVIDE				= "provide";
65
64
66
	private final static int	ACTION_REQUIRE			= 0x00000001;
65
	private final static int						ACTION_REQUIRE		= 0x00000001;
67
	private final static int	ACTION_PROVIDE		= 0x00000002;
66
	private final static int						ACTION_PROVIDE		= 0x00000002;
68
	private final static int	ACTION_ALL			= ACTION_REQUIRE
67
	private final static int						ACTION_ALL			= ACTION_REQUIRE
69
															| ACTION_PROVIDE;
68
																				| ACTION_PROVIDE;
70
	final static int						ACTION_NONE			= 0;
69
	final static int								ACTION_NONE			= 0;
71
70
72
	/**
71
	/**
73
	 * The actions mask.
72
	 * The actions mask.
74
	 */
73
	 */
75
	transient int							action_mask;
74
	transient int									action_mask;
76
75
77
	/**
76
	/**
78
	 * The actions in canonical form.
77
	 * The actions in canonical form.
79
	 * 
78
	 * 
80
	 * @serial
79
	 * @serial
81
	 */
80
	 */
82
	private volatile String		actions				= null;
81
	private volatile String							actions				= null;
83
82
84
	/**
83
	/**
85
	 * The service used by this ServicePermission. Must be null if not
84
	 * The attributes of the requested capability. Must be null if not
86
	 * constructed with a service.
85
	 * constructed with attributes.
87
	 */
86
	 */
88
	transient final ServiceReference< ? >					service;
87
	transient final Map<String, Object>				attributes;
89
88
90
	/**
89
	/**
91
	 * The object classes for this ServicePermission. Must be null if not
90
	 * The bundle of the requested capability. Must be null if not constructed
92
	 * constructed with a service.
91
	 * with bundle.
93
	 */
92
	 */
94
	transient final String[]				objectClass;
93
	transient final Bundle							bundle;
95
94
96
	/**
95
	/**
97
	 * If this ServicePermission was constructed with a filter, this holds a
96
	 * If this CapabilityPermission was constructed with a filter, this holds a
98
	 * Filter matching object used to evaluate the filter in implies.
97
	 * Filter matching object used to evaluate the filter in implies.
99
	 */
98
	 */
100
	transient Filter						filter;
99
	transient Filter								filter;
101
100
102
	/**
101
	/**
103
	 * This dictionary holds the properties of the permission, used to match a
102
	 * This map holds the properties of the permission, used to match a filter
104
	 * filter in implies. This is not initialized until necessary, and then
103
	 * in implies. This is not initialized until necessary, and then cached in
105
	 * cached in this object.
104
	 * this object.
106
	 */
105
	 */
107
	private transient volatile Map<String, Object>	properties;
106
	private transient volatile Map<String, Object>	properties;
108
107
109
	/**
108
	/**
110
	 * True if constructed with a name and the name is "*" or ends with ".*".
111
	 */
112
	private transient boolean				wildcard;
113
114
	/**
115
	 * If constructed with a name and the name ends with ".*", this contains the
116
	 * name without the final "*".
117
	 */
118
	private transient String				prefix;
119
120
	/**
121
	 * Create a new CapabilityPermission.
109
	 * Create a new CapabilityPermission.
122
	 * 
110
	 * 
123
	 * <p>
111
	 * <p>
Lines 187-235 Link Here
187
	 * @param providingBundle The bundle providing the requested capability.
175
	 * @param providingBundle The bundle providing the requested capability.
188
	 * @param actions The action {@code require}.
176
	 * @param actions The action {@code require}.
189
	 * @throws IllegalArgumentException If the specified action is not
177
	 * @throws IllegalArgumentException If the specified action is not
190
	 *         {@code require} or any parameters are {@code null}.
178
	 *         {@code require} or attributes or providingBundle are {@code null}
179
	 *         .
191
	 */
180
	 */
192
	public CapabilityPermission(String namespace, Map<String, ? > attributes,
181
	public CapabilityPermission(String namespace, Map<String, ? > attributes,
193
			Bundle providingBundle, String actions) {
182
			Bundle providingBundle, String actions) {
194
		super(namespace);
183
		super(namespace);
195
		this.objectClass = null;
184
		setTransients(namespace, parseActions(actions));
196
		this.service = null;
185
		if (attributes == null) {
197
		// setTransients(null, parseActions(actions));
186
			throw new IllegalArgumentException("attributes must not be null");
198
		// this.service = reference;
187
		}
199
		// this.objectClass = (String[]) reference
188
		if (providingBundle == null) {
200
		// .getProperty(Constants.OBJECTCLASS);
189
			throw new IllegalArgumentException("bundle must not be null");
190
		}
191
		this.attributes = new HashMap<String, Object>(attributes);
192
		this.bundle = providingBundle;
201
		if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) {
193
		if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) {
202
			throw new IllegalArgumentException("invalid action string");
194
			throw new IllegalArgumentException("invalid action string");
203
		}
195
		}
204
	}
196
	}
205
197
206
	/**
198
	/**
207
	 * Create a permission name from a ServiceReference
199
	 * Package private constructor used by CapabilityPermissionCollection.
208
	 * 
209
	 * @param reference ServiceReference to use to create permission name.
210
	 * @return permission name.
211
	 */
212
	private static String createName(ServiceReference< ? > reference) {
213
		if (reference == null) {
214
			throw new IllegalArgumentException("reference must not be null");
215
		}
216
		StringBuffer sb = new StringBuffer("(service.id=");
217
		sb.append(reference.getProperty(Constants.SERVICE_ID));
218
		sb.append(")");
219
		return sb.toString();
220
	}
221
222
	/**
223
	 * Package private constructor used by ServicePermissionCollection.
224
	 * 
200
	 * 
225
	 * @param name class name
201
	 * @param name class name
226
	 * @param mask action mask
202
	 * @param mask action mask
227
	 */
203
	 */
228
	CapabilityPermission(String name, int mask) {
204
	CapabilityPermission(String name, int mask) {
229
		super(name);
205
		super(name);
230
		setTransients(parseFilter(name), mask);
206
		setTransients(name, mask);
231
		this.service = null;
207
		this.attributes = null;
232
		this.objectClass = null;
208
		this.bundle = null;
233
	}
209
	}
234
210
235
	/**
211
	/**
Lines 237-258 Link Here
237
	 * 
213
	 * 
238
	 * @param mask action mask
214
	 * @param mask action mask
239
	 */
215
	 */
240
	private void setTransients(Filter f, int mask) {
216
	private void setTransients(String name, int mask) {
241
		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
217
		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
242
			throw new IllegalArgumentException("invalid action string");
218
			throw new IllegalArgumentException("invalid action string");
243
		}
219
		}
244
		action_mask = mask;
220
		action_mask = mask;
245
		filter = f;
221
		filter = parseFilter(name);
246
		if (f == null) {
247
			String name = getName();
248
			int l = name.length();
249
			/* if "*" or endsWith ".*" */
250
			wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name
251
					.charAt(l - 2) == '.')));
252
			if (wildcard && (l > 1)) {
253
				prefix = name.substring(0, l - 1);
254
			}
255
		}
256
	}
222
	}
257
223
258
	/**
224
	/**
Lines 288-312 Link Here
288
			// check for the known strings
254
			// check for the known strings
289
			int matchlen;
255
			int matchlen;
290
256
291
			if (i >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G')
257
			if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R')
292
					&& (a[i - 1] == 'e' || a[i - 1] == 'E')
258
					&& (a[i - 5] == 'e' || a[i - 5] == 'E')
293
					&& (a[i] == 't' || a[i] == 'T')) {
259
					&& (a[i - 4] == 'q' || a[i - 4] == 'Q')
294
				matchlen = 3;
260
					&& (a[i - 3] == 'u' || a[i - 3] == 'U')
261
					&& (a[i - 2] == 'i' || a[i - 2] == 'I')
262
					&& (a[i - 1] == 'r' || a[i - 1] == 'R')
263
					&& (a[i] == 'e' || a[i] == 'E')) {
264
				matchlen = 7;
295
				mask |= ACTION_REQUIRE;
265
				mask |= ACTION_REQUIRE;
296
297
			}
266
			}
298
			else
267
			else
299
				if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R')
268
				if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P')
300
						&& (a[i - 6] == 'e' || a[i - 6] == 'E')
269
						&& (a[i - 5] == 'r' || a[i - 5] == 'R')
301
						&& (a[i - 5] == 'g' || a[i - 5] == 'G')
270
						&& (a[i - 4] == 'o' || a[i - 4] == 'O')
302
						&& (a[i - 4] == 'i' || a[i - 4] == 'I')
271
						&& (a[i - 3] == 'v' || a[i - 3] == 'V')
303
						&& (a[i - 3] == 's' || a[i - 3] == 'S')
272
						&& (a[i - 2] == 'i' || a[i - 2] == 'I')
304
						&& (a[i - 2] == 't' || a[i - 2] == 'T')
273
						&& (a[i - 1] == 'd' || a[i - 1] == 'D')
305
						&& (a[i - 1] == 'e' || a[i - 1] == 'E')
274
						&& (a[i] == 'e' || a[i] == 'E')) {
306
						&& (a[i] == 'r' || a[i] == 'R')) {
275
					matchlen = 7;
307
					matchlen = 8;
308
					mask |= ACTION_PROVIDE;
276
					mask |= ACTION_PROVIDE;
309
310
				}
277
				}
311
				else {
278
				else {
312
					// parse error
279
					// parse error
Lines 315-327 Link Here
315
				}
282
				}
316
283
317
			// make sure we didn't just match the tail of a word
284
			// make sure we didn't just match the tail of a word
318
			// like "ackbarfregister". Also, skip to the comma.
285
			// like "ackbarfprovide". Also, skip to the comma.
319
			seencomma = false;
286
			seencomma = false;
320
			while (i >= matchlen && !seencomma) {
287
			while (i >= matchlen && !seencomma) {
321
				switch (a[i - matchlen]) {
288
				switch (a[i - matchlen]) {
322
					case ',' :
289
					case ',' :
323
						seencomma = true;
290
						seencomma = true;
324
					/* FALLTHROUGH */
291
						/* FALLTHROUGH */
325
					case ' ' :
292
					case ' ' :
326
					case '\r' :
293
					case '\r' :
327
					case '\n' :
294
					case '\n' :
Lines 384-390 Link Here
384
			return false;
351
			return false;
385
		}
352
		}
386
		CapabilityPermission requested = (CapabilityPermission) p;
353
		CapabilityPermission requested = (CapabilityPermission) p;
387
		if (service != null) {
354
		if (bundle != null) {
388
			return false;
355
			return false;
389
		}
356
		}
390
		// if requested permission has a filter, then it is an invalid argument
357
		// if requested permission has a filter, then it is an invalid argument
Lines 398-405 Link Here
398
	 * Internal implies method. Used by the implies and the permission
365
	 * Internal implies method. Used by the implies and the permission
399
	 * collection implies methods.
366
	 * collection implies methods.
400
	 * 
367
	 * 
401
	 * @param requested The requested ServicePermission which has already be
368
	 * @param requested The requested CapabilityPermission which has already be
402
	 *        validated as a proper argument. The requested ServicePermission
369
	 *        validated as a proper argument. The requested CapabilityPermission
403
	 *        must not have a filter expression.
370
	 *        must not have a filter expression.
404
	 * @param effective The effective actions with which to start.
371
	 * @param effective The effective actions with which to start.
405
	 * @return {@code true} if the specified permission is implied by this
372
	 * @return {@code true} if the specified permission is implied by this
Lines 412-451 Link Here
412
		if ((effective & desired) != desired) {
379
		if ((effective & desired) != desired) {
413
			return false;
380
			return false;
414
		}
381
		}
415
		/* we have name of "*" */
382
		/* Get filter if any */
416
		if (wildcard && (prefix == null)) {
417
			return true;
418
		}
419
		/* if we have a filter */
420
		Filter f = filter;
383
		Filter f = filter;
421
		if (f != null) {
384
		if (f == null) {
422
			return f.matches(requested.getProperties());
423
		}
424
		/* if requested permission not created with ServiceReference */
425
		String[] requestedNames = requested.objectClass;
426
		if (requestedNames == null) {
427
			return super.implies(requested);
385
			return super.implies(requested);
428
		}
386
		}
429
		/* requested permission created with ServiceReference */
387
		return f.matches(requested.getProperties());
430
		if (wildcard) {
431
			int pl = prefix.length();
432
			for (int i = 0, l = requestedNames.length; i < l; i++) {
433
				String requestedName = requestedNames[i];
434
				if ((requestedName.length() > pl)
435
						&& requestedName.startsWith(prefix)) {
436
					return true;
437
				}
438
			}
439
		}
440
		else {
441
			String name = getName();
442
			for (int i = 0, l = requestedNames.length; i < l; i++) {
443
				if (requestedNames[i].equals(name)) {
444
					return true;
445
				}
446
			}
447
		}
448
		return false;
449
	}
388
	}
450
389
451
	/**
390
	/**
Lines 510-521 Link Here
510
			return false;
449
			return false;
511
		}
450
		}
512
451
513
		CapabilityPermission sp = (CapabilityPermission) obj;
452
		CapabilityPermission cp = (CapabilityPermission) obj;
514
453
515
		return (action_mask == sp.action_mask)
454
		return (action_mask == cp.action_mask)
516
				&& getName().equals(sp.getName())
455
				&& getName().equals(cp.getName())
517
				&& ((service == sp.service) || ((service != null) && (service
456
				&& ((attributes == cp.attributes) || ((attributes != null) && (attributes
518
						.compareTo(sp.service) == 0)));
457
						.equals(cp.attributes))))
458
				&& ((bundle == cp.bundle) || ((bundle != null) && bundle
459
						.equals(cp.bundle)));
519
	}
460
	}
520
461
521
	/**
462
	/**
Lines 526-533 Link Here
526
	public int hashCode() {
467
	public int hashCode() {
527
		int h = 31 * 17 + getName().hashCode();
468
		int h = 31 * 17 + getName().hashCode();
528
		h = 31 * h + getActions().hashCode();
469
		h = 31 * h + getActions().hashCode();
529
		if (service != null) {
470
		if (attributes != null) {
530
			h = 31 * h + service.hashCode();
471
			h = 31 * h + attributes.hashCode();
472
		}
473
		if (bundle != null) {
474
			h = 31 * h + bundle.hashCode();
531
		}
475
		}
532
		return h;
476
		return h;
533
	}
477
	}
Lines 538-544 Link Here
538
	 */
482
	 */
539
	private synchronized void writeObject(java.io.ObjectOutputStream s)
483
	private synchronized void writeObject(java.io.ObjectOutputStream s)
540
			throws IOException {
484
			throws IOException {
541
		if (service != null) {
485
		if (bundle != null) {
542
			throw new NotSerializableException("cannot serialize");
486
			throw new NotSerializableException("cannot serialize");
543
		}
487
		}
544
		// Write out the actions. The superclass takes care of the name
488
		// Write out the actions. The superclass takes care of the name
Lines 556-610 Link Here
556
			throws IOException, ClassNotFoundException {
500
			throws IOException, ClassNotFoundException {
557
		// Read in the action, then initialize the rest
501
		// Read in the action, then initialize the rest
558
		s.defaultReadObject();
502
		s.defaultReadObject();
559
		setTransients(parseFilter(getName()), parseActions(actions));
503
		setTransients(getName(), parseActions(actions));
560
	}
504
	}
505
561
	/**
506
	/**
562
	 * Called by {@code <@link ServicePermission#implies(Permission)>}.
507
	 * Called by {@code <@link CapabilityPermission#implies(Permission)>}. This
508
	 * method is only called on a requested permission which cannot have a
509
	 * filter set.
563
	 * 
510
	 * 
564
	 * @return a dictionary of properties for this permission.
511
	 * @return a map of properties for this permission.
565
	 */
512
	 */
566
	private Map<String, Object> getProperties() {
513
	private Map<String, Object> getProperties() {
567
		Map<String, Object> result = properties;
514
		Map<String, Object> result = properties;
568
		if (result != null) {
515
		if (result != null) {
569
			return result;
516
			return result;
570
		}
517
		}
571
		if (service == null) {
518
		final Map<String, Object> props = new HashMap<String, Object>(5);
572
			result = new HashMap<String, Object>(1);
519
		props.put("capability.namespace", getName());
573
			if (filter == null) {
520
		if (bundle == null) {
574
				result.put(Constants.OBJECTCLASS, new String[] {getName()});
521
			return properties = props;
575
			}
522
		}
576
			return properties = result;
523
		AccessController.doPrivileged(new PrivilegedAction<Object>() {
577
		}
524
			public Object run() {
578
		final Map<String, Object> props = new HashMap<String, Object>(4);
525
				props.put("id", new Long(bundle.getBundleId()));
579
		final Bundle bundle = service.getBundle();
526
				props.put("location", bundle.getLocation());
580
		if (bundle != null) {
527
				String name = bundle.getSymbolicName();
581
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
528
				if (name != null) {
582
				public Object run() {
529
					props.put("name", name);
583
					props.put("id", new Long(bundle.getBundleId()));
530
				}
584
					props.put("location", bundle.getLocation());
531
				SignerProperty signer = new SignerProperty(bundle);
585
					String name = bundle.getSymbolicName();
532
				if (signer.isBundleSigned()) {
586
					if (name != null) {
533
					props.put("signer", signer);
587
						props.put("name", name);
588
					}
589
					SignerProperty signer = new SignerProperty(bundle);
590
					if (signer.isBundleSigned()) {
591
						props.put("signer", signer);
592
					}
593
					return null;
594
				}
534
				}
595
			});
535
				return null;
596
		}
536
			}
597
		return properties = new Properties(props, service);
537
		});
538
		return properties = new Properties(props, attributes);
598
	}
539
	}
599
	
540
600
	private static class Properties extends AbstractMap<String, Object> {
541
	private static class Properties extends AbstractMap<String, Object> {
601
		private final Map<String, Object>	properties;
542
		private final Map<String, Object>							properties;
602
		private final ServiceReference< ? >	service;
543
		private final Map<String, Object>							attributes;
603
		private transient volatile Set<Map.Entry<String, Object>>	entries;
544
		private transient volatile Set<Map.Entry<String, Object>>	entries;
604
545
605
		Properties(Map<String, Object> properties, ServiceReference< ? > service) {
546
		Properties(Map<String, Object> properties,
547
				Map<String, Object> attributes) {
606
			this.properties = properties;
548
			this.properties = properties;
607
			this.service = service;
549
			this.attributes = attributes;
608
			entries = null;
550
			entries = null;
609
		}
551
		}
610
552
Lines 614-626 Link Here
614
			}
556
			}
615
			String key = (String) k;
557
			String key = (String) k;
616
			if (key.charAt(0) == '@') {
558
			if (key.charAt(0) == '@') {
617
				return service.getProperty(key.substring(1));
559
				return attributes.get(key.substring(1));
618
			}
560
			}
619
			Object value = properties.get(key);
561
			Object value = properties.get(key);
620
			if (value != null) { // fall back to service properties
562
			if (value != null) { // fall back to service properties
621
				return value;
563
				return value;
622
			}
564
			}
623
			return service.getProperty(key);
565
			return attributes.get(key);
624
		}
566
		}
625
567
626
		public Set<Map.Entry<String, Object>> entrySet() {
568
		public Set<Map.Entry<String, Object>> entrySet() {
Lines 628-705 Link Here
628
				return entries;
570
				return entries;
629
			}
571
			}
630
			Set<Map.Entry<String, Object>> all = new HashSet<Map.Entry<String, Object>>(
572
			Set<Map.Entry<String, Object>> all = new HashSet<Map.Entry<String, Object>>(
631
					properties.entrySet());
573
					attributes.size() + properties.size());
632
			add: for (String key : service.getPropertyKeys()) {
574
			all.addAll(attributes.entrySet());
633
				for (String k : properties.keySet()) {
575
			all.addAll(properties.entrySet());
634
					if (key.equalsIgnoreCase(k)) {
635
						continue add;
636
					}
637
				}
638
				all.add(new Entry(key, service.getProperty(key)));
639
			}
640
			return entries = Collections.unmodifiableSet(all);
576
			return entries = Collections.unmodifiableSet(all);
641
		}
577
		}
642
		
643
		private static class Entry implements Map.Entry<String, Object> {
644
			private final String	k;
645
			private final Object	v;
646
647
			Entry(String key, Object value) {
648
				this.k = key;
649
				this.v = value;
650
			}
651
			public String getKey() {
652
				return k;
653
			}
654
			public Object getValue() {
655
				return v;
656
			}
657
			public Object setValue(Object value) {
658
				throw new UnsupportedOperationException();
659
			}
660
			public String toString() {
661
				return k + "=" + v;
662
			}
663
			public int hashCode() {
664
				return ((k == null) ? 0 : k.hashCode())
665
						^ ((v == null) ? 0 : v.hashCode());
666
			}
667
			public boolean equals(Object obj) {
668
				if (obj == this) {
669
					return true;
670
				}
671
				if (!(obj instanceof Map.Entry)) {
672
					return false;
673
				}
674
				Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) obj;
675
				final Object key = e.getKey();
676
				if ((k == key) || ((k != null) && k.equals(key))) {
677
					final Object value = e.getValue();
678
					if ((v == value) || ((v != null) && v.equals(value))) {
679
						return true;
680
					}
681
				}
682
				return false;
683
			}
684
		}
685
	}
578
	}
686
}
579
}
687
580
688
/**
581
/**
689
 * Stores a set of ServicePermission permissions.
582
 * Stores a set of CapabilityPermission permissions.
690
 * 
583
 * 
691
 * @see java.security.Permission
584
 * @see java.security.Permission
692
 * @see java.security.Permissions
585
 * @see java.security.Permissions
693
 * @see java.security.PermissionCollection
586
 * @see java.security.PermissionCollection
694
 */
587
 */
695
final class CapabilityPermissionCollection extends PermissionCollection {
588
final class CapabilityPermissionCollection extends PermissionCollection {
696
	static final long	serialVersionUID	= 662615640374640621L;
589
	static final long							serialVersionUID	= -615322242639008920L;
590
697
	/**
591
	/**
698
	 * Table of permissions.
592
	 * Table of permissions.
699
	 * 
593
	 * 
594
	 * @serial
700
	 * @GuardedBy this
595
	 * @GuardedBy this
701
	 */
596
	 */
702
	private transient Map<String, CapabilityPermission>	permissions;
597
	private Map<String, CapabilityPermission>	permissions;
703
598
704
	/**
599
	/**
705
	 * Boolean saying if "*" is in the collection.
600
	 * Boolean saying if "*" is in the collection.
Lines 707-713 Link Here
707
	 * @serial
602
	 * @serial
708
	 * @GuardedBy this
603
	 * @GuardedBy this
709
	 */
604
	 */
710
	private boolean		all_allowed;
605
	private boolean								all_allowed;
711
606
712
	/**
607
	/**
713
	 * Table of permissions with filter expressions.
608
	 * Table of permissions with filter expressions.
Lines 715-721 Link Here
715
	 * @serial
610
	 * @serial
716
	 * @GuardedBy this
611
	 * @GuardedBy this
717
	 */
612
	 */
718
	private Map<String, CapabilityPermission>				filterPermissions;
613
	private Map<String, CapabilityPermission>	filterPermissions;
719
614
720
	/**
615
	/**
721
	 * Creates an empty CapabilityPermissionCollection object.
616
	 * Creates an empty CapabilityPermissionCollection object.
Lines 730-739 Link Here
730
	 * 
625
	 * 
731
	 * @param permission The Permission object to add.
626
	 * @param permission The Permission object to add.
732
	 * @throws IllegalArgumentException If the specified permission is not a
627
	 * @throws IllegalArgumentException If the specified permission is not a
733
	 *         ServicePermission object.
628
	 *         CapabilityPermission object.
734
	 * @throws SecurityException If this
629
	 * @throws SecurityException If this {@code CapabilityPermissionCollection}
735
	 *         {@code ServicePermissionCollection} object has been marked
630
	 *         object has been marked read-only.
736
	 *         read-only.
737
	 */
631
	 */
738
	public void add(final Permission permission) {
632
	public void add(final Permission permission) {
739
		if (!(permission instanceof CapabilityPermission)) {
633
		if (!(permission instanceof CapabilityPermission)) {
Lines 745-758 Link Here
745
					+ "readonly PermissionCollection");
639
					+ "readonly PermissionCollection");
746
		}
640
		}
747
641
748
		final CapabilityPermission sp = (CapabilityPermission) permission;
642
		final CapabilityPermission cp = (CapabilityPermission) permission;
749
		if (sp.service != null) {
643
		if (cp.bundle != null) {
750
			throw new IllegalArgumentException("cannot add to collection: "
644
			throw new IllegalArgumentException("cannot add to collection: "
751
					+ sp);
645
					+ cp);
752
		}
646
		}
753
		
647
754
		final String name = sp.getName();
648
		final String name = cp.getName();
755
		final Filter f = sp.filter;
649
		final Filter f = cp.filter;
756
		synchronized (this) {
650
		synchronized (this) {
757
			/* select the bucket for the permission */
651
			/* select the bucket for the permission */
758
			Map<String, CapabilityPermission> pc;
652
			Map<String, CapabilityPermission> pc;
Lines 766-785 Link Here
766
				pc = permissions;
660
				pc = permissions;
767
			}
661
			}
768
			final CapabilityPermission existing = pc.get(name);
662
			final CapabilityPermission existing = pc.get(name);
769
			
663
770
			if (existing != null) {
664
			if (existing != null) {
771
				final int oldMask = existing.action_mask;
665
				final int oldMask = existing.action_mask;
772
				final int newMask = sp.action_mask;
666
				final int newMask = cp.action_mask;
773
				if (oldMask != newMask) {
667
				if (oldMask != newMask) {
774
					pc
668
					pc.put(name, new CapabilityPermission(name, oldMask
775
							.put(name, new CapabilityPermission(name, oldMask
776
							| newMask));
669
							| newMask));
777
				}
670
				}
778
			}
671
			}
779
			else {
672
			else {
780
				pc.put(name, sp);
673
				pc.put(name, cp);
781
			}
674
			}
782
			
675
783
			if (!all_allowed) {
676
			if (!all_allowed) {
784
				if (name.equals("*")) {
677
				if (name.equals("*")) {
785
					all_allowed = true;
678
					all_allowed = true;
Lines 793-801 Link Here
793
	 * {@code permission}.
686
	 * {@code permission}.
794
	 * 
687
	 * 
795
	 * @param permission The Permission object to compare.
688
	 * @param permission The Permission object to compare.
796
	 * @return {@code true} if {@code permission} is a proper
689
	 * @return {@code true} if {@code permission} is a proper subset of a
797
	 *         subset of a permission in the set; {@code false}
690
	 *         permission in the set; {@code false} otherwise.
798
	 *         otherwise.
799
	 */
691
	 */
800
	public boolean implies(final Permission permission) {
692
	public boolean implies(final Permission permission) {
801
		if (!(permission instanceof CapabilityPermission)) {
693
		if (!(permission instanceof CapabilityPermission)) {
Lines 807-850 Link Here
807
			return false;
699
			return false;
808
		}
700
		}
809
701
702
		String requestedName = requested.getName();
703
		final int desired = requested.action_mask;
810
		int effective = CapabilityPermission.ACTION_NONE;
704
		int effective = CapabilityPermission.ACTION_NONE;
705
811
		Collection<CapabilityPermission> perms;
706
		Collection<CapabilityPermission> perms;
812
		synchronized (this) {
707
		synchronized (this) {
813
			final int desired = requested.action_mask;
708
			Map<String, CapabilityPermission> pc = permissions;
709
			CapabilityPermission cp;
814
			/* short circuit if the "*" Permission was added */
710
			/* short circuit if the "*" Permission was added */
815
			if (all_allowed) {
711
			if (all_allowed) {
816
				CapabilityPermission sp = permissions.get("*");
712
				cp = pc.get("*");
817
				if (sp != null) {
713
				if (cp != null) {
818
					effective |= sp.action_mask;
714
					effective |= cp.action_mask;
819
					if ((effective & desired) == desired) {
715
					if ((effective & desired) == desired) {
820
						return true;
716
						return true;
821
					}
717
					}
822
				}
718
				}
823
			}
719
			}
824
			
720
825
			String[] requestedNames = requested.objectClass;
721
			/*
826
			/* if requested permission not created with ServiceReference */
722
			 * strategy: Check for full match first. Then work our way up the
827
			if (requestedNames == null) {
723
			 * name looking for matches on a.b.*
828
				effective |= effective(requested.getName(), desired, effective);
724
			 */
725
			cp = pc.get(requestedName);
726
			if (cp != null) {
727
				/* we have a direct hit! */
728
				effective |= cp.action_mask;
829
				if ((effective & desired) == desired) {
729
				if ((effective & desired) == desired) {
830
					return true;
730
					return true;
831
				}
731
				}
832
			}
732
			}
833
			/* requested permission created with ServiceReference */
733
			/* work our way up the tree... */
834
			else {
734
			int last;
835
				for (int i = 0, l = requestedNames.length; i < l; i++) {
735
			int offset = requestedName.length() - 1;
836
					if ((effective(requestedNames[i], desired, effective) & desired) == desired) {
736
			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
737
				requestedName = requestedName.substring(0, last + 1) + "*";
738
				cp = pc.get(requestedName);
739
				if (cp != null) {
740
					effective |= cp.action_mask;
741
					if ((effective & desired) == desired) {
837
						return true;
742
						return true;
838
					}
743
					}
839
				}
744
				}
745
				offset = last - 1;
840
			}
746
			}
841
			Map<String, CapabilityPermission> pc = filterPermissions;
747
			/*
748
			 * we don't have to check for "*" as it was already checked before
749
			 * we were called.
750
			 */
751
			pc = filterPermissions;
842
			if (pc == null) {
752
			if (pc == null) {
843
				return false;
753
				return false;
844
			}
754
			}
845
			perms = pc.values();
755
			perms = pc.values();
846
		}
756
		}
847
		
848
		/* iterate one by one over filteredPermissions */
757
		/* iterate one by one over filteredPermissions */
849
		for (CapabilityPermission perm : perms) {
758
		for (CapabilityPermission perm : perms) {
850
			if (perm.implies0(requested, effective)) {
759
			if (perm.implies0(requested, effective)) {
Lines 855-908 Link Here
855
	}
764
	}
856
765
857
	/**
766
	/**
858
	 * Consult permissions map to compute the effective permission for the
767
	 * Returns an enumeration of all the {@code CapabilityPermission} objects in
859
	 * requested permission name.
768
	 * the container.
860
	 * 
861
	 * @param requestedName The requested service name.
862
	 * @param desired The desired actions.
863
	 * @param effective The effective actions.
864
	 * @return The new effective actions.
865
	 */
866
	private int effective(String requestedName, final int desired,
867
			int effective) {
868
		final Map<String, CapabilityPermission> pc = permissions;
869
		CapabilityPermission sp = pc.get(requestedName);
870
		// strategy:
871
		// Check for full match first. Then work our way up the
872
		// name looking for matches on a.b.*
873
		if (sp != null) {
874
			// we have a direct hit!
875
			effective |= sp.action_mask;
876
			if ((effective & desired) == desired) {
877
				return effective;
878
			}
879
		}
880
		// work our way up the tree...
881
		int last;
882
		int offset = requestedName.length() - 1;
883
		while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
884
			requestedName = requestedName.substring(0, last + 1) + "*";
885
			sp = pc.get(requestedName);
886
			if (sp != null) {
887
				effective |= sp.action_mask;
888
				if ((effective & desired) == desired) {
889
					return effective;
890
				}
891
			}
892
			offset = last - 1;
893
		}
894
		/*
895
		 * we don't have to check for "*" as it was already checked before we
896
		 * were called.
897
		 */
898
		return effective;
899
	}
900
	
901
	/**
902
	 * Returns an enumeration of all the {@code ServicePermission}
903
	 * objects in the container.
904
	 * 
769
	 * 
905
	 * @return Enumeration of all the ServicePermission objects.
770
	 * @return Enumeration of all the CapabilityPermission objects.
906
	 */
771
	 */
907
	public synchronized Enumeration<Permission> elements() {
772
	public synchronized Enumeration<Permission> elements() {
908
		List<Permission> all = new ArrayList<Permission>(permissions.values());
773
		List<Permission> all = new ArrayList<Permission>(permissions.values());
Lines 912-930 Link Here
912
		}
777
		}
913
		return Collections.enumeration(all);
778
		return Collections.enumeration(all);
914
	}
779
	}
915
	
780
916
	/* serialization logic */
781
	/* serialization logic */
917
	private static final ObjectStreamField[]	serialPersistentFields	= {
782
	private static final ObjectStreamField[]	serialPersistentFields	= {
918
			new ObjectStreamField("permissions", Hashtable.class),
783
			new ObjectStreamField("permissions", HashMap.class),
919
			new ObjectStreamField("all_allowed", Boolean.TYPE),
784
			new ObjectStreamField("all_allowed", Boolean.TYPE),
920
			new ObjectStreamField("filterPermissions", HashMap.class)	};
785
			new ObjectStreamField("filterPermissions", HashMap.class)	};
921
786
922
	private synchronized void writeObject(ObjectOutputStream out)
787
	private synchronized void writeObject(ObjectOutputStream out)
923
			throws IOException {
788
			throws IOException {
924
		Hashtable<String, CapabilityPermission> hashtable = new Hashtable<String, CapabilityPermission>(
925
				permissions);
926
		ObjectOutputStream.PutField pfields = out.putFields();
789
		ObjectOutputStream.PutField pfields = out.putFields();
927
		pfields.put("permissions", hashtable);
790
		pfields.put("permissions", permissions);
928
		pfields.put("all_allowed", all_allowed);
791
		pfields.put("all_allowed", all_allowed);
929
		pfields.put("filterPermissions", filterPermissions);
792
		pfields.put("filterPermissions", filterPermissions);
930
		out.writeFields();
793
		out.writeFields();
Lines 933-941 Link Here
933
	private synchronized void readObject(java.io.ObjectInputStream in)
796
	private synchronized void readObject(java.io.ObjectInputStream in)
934
			throws IOException, ClassNotFoundException {
797
			throws IOException, ClassNotFoundException {
935
		ObjectInputStream.GetField gfields = in.readFields();
798
		ObjectInputStream.GetField gfields = in.readFields();
936
		Hashtable<String, CapabilityPermission> hashtable = (Hashtable<String, CapabilityPermission>) gfields
799
		HashMap<String, CapabilityPermission> p = (HashMap<String, CapabilityPermission>) gfields
937
				.get("permissions", null);
800
				.get("permissions", null);
938
		permissions = new HashMap<String, CapabilityPermission>(hashtable);
801
		permissions = p;
939
		all_allowed = gfields.get("all_allowed", false);
802
		all_allowed = gfields.get("all_allowed", false);
940
		HashMap<String, CapabilityPermission> fp = (HashMap<String, CapabilityPermission>) gfields
803
		HashMap<String, CapabilityPermission> fp = (HashMap<String, CapabilityPermission>) gfields
941
				.get("filterPermissions", null);
804
				.get("filterPermissions", null);
(-)osgi/src/org/osgi/framework/hooks/resolver/ResolverHook.java (-26 / +26 lines)
Lines 24-35 Link Here
24
import org.osgi.framework.wiring.FrameworkWiring;
24
import org.osgi.framework.wiring.FrameworkWiring;
25
25
26
/**
26
/**
27
 * OSGi Framework Resolver Hook Service.
27
 * OSGi Framework Resolver Hook instances are obtained from the OSGi {@link ResolverHookFactory
28
 * Framework Resolver Hook Factory} service.  
28
 * 
29
 * 
29
 * <p>
30
 * <p>
30
 * Services registered with this service interface will be called by the framework during a resolve
31
 * A Resolver Hook instance is called by the framework during a resolve
31
 * process.  The framework must, at most, have one resolve process running at any given point 
32
 * process.  A resolver hook may influence the outcome of a resolve process by removing entries
32
 * in time.  A resolver hook may influence the outcome of a resolve process by removing entries
33
 * from shrinkable collections that are passed to the hook during a resolve process.  A shrinkable 
33
 * from shrinkable collections that are passed to the hook during a resolve process.  A shrinkable 
34
 * collection is a {@code Collection} that supports all remove operations.  Any other attempts to modify
34
 * collection is a {@code Collection} that supports all remove operations.  Any other attempts to modify
35
 * a shrinkable collection will result in an {@code UnsupportedOperationException} being thrown.
35
 * a shrinkable collection will result in an {@code UnsupportedOperationException} being thrown.
Lines 37-54 Link Here
37
 * The following steps outline the way a framework uses the resolver hooks during a resolve
37
 * The following steps outline the way a framework uses the resolver hooks during a resolve
38
 * process.
38
 * process.
39
 * <ol>
39
 * <ol>
40
 *  <li> Collect a snapshot of registered resolver hooks that will be called during the
40
 *  <li> Collect a snapshot of registered resolver hook factories that will be called during the
41
 *       current resolve process.  Any hooks registered after the snapshot is taken must not be called
41
 *       current resolve process.  Any hook factories registered after the snapshot is taken must not be called
42
 *       during the current resolve process.  A resolver hook contained in the snapshot may become
42
 *       during the current resolve process.  A resolver hook factory contained in the snapshot may become
43
 *       unregistered during the resolve process.  The framework should handle this and stop calling
43
 *       unregistered during the resolve process.  The framework should handle this and stop calling
44
 *       the unregistered hook for the remainder of the resolve process.</li>
44
 *       the resolver hook instance provided by the unregistered hook factory for the remainder of the resolve process.</li>
45
 *  <li> For each registered hook call the {@link #begin()} method to inform the hooks about a resolve 
45
 *  <li> For each registered hook factory call the {@link ResolverHookFactory#begin(Collection)} method to inform the 
46
 *       process beginning.</li>
46
 *       hooks about a resolve process beginning and to obtain a Resolver Hook instance that will be used for the duration
47
 *       of the resolve process.</li>
47
 *  <li> Determine the collection of unresolved bundle revisions that may be considered for resolution during
48
 *  <li> Determine the collection of unresolved bundle revisions that may be considered for resolution during
48
 *       the current resolution process and place each of the bundle revisions in a shrinkable collection
49
 *       the current resolution process and place each of the bundle revisions in a shrinkable collection
49
 *       <b>{@code R}</b>.
50
 *       <b>{@code R}</b>.
50
 *       <ol type="a">
51
 *       <ol type="a">
51
 *         <li> For each registered hook call the {@link #filterResolvable(Collection)} method with the 
52
 *         <li> For each resolver hook call the {@link #filterResolvable(Collection)} method with the 
52
 *              shrinkable collection <b>{@code R}</b>.</li>
53
 *              shrinkable collection <b>{@code R}</b>.</li>
53
 *       </ol>
54
 *       </ol>
54
 *  </li>
55
 *  </li>
Lines 66-72 Link Here
66
 *         <li> Remove the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by
67
 *         <li> Remove the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by
67
 *              bundle revision <b>{@code B}</b> from shrinkable collection <b>{@code S}</b>.  A singleton bundle 
68
 *              bundle revision <b>{@code B}</b> from shrinkable collection <b>{@code S}</b>.  A singleton bundle 
68
 *              cannot collide with itself.</li>
69
 *              cannot collide with itself.</li>
69
 *         <li> For each registered hook call the {@link #filterSingletonCollisions(Capability, Collection)}
70
 *         <li> For each resovler hook call the {@link #filterSingletonCollisions(Capability, Collection)}
70
 *              with the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by bundle revision 
71
 *              with the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by bundle revision 
71
 *              <b>{@code B}</b> and the shrinkable collection <b>{@code S}</b></li>
72
 *              <b>{@code B}</b> and the shrinkable collection <b>{@code S}</b></li>
72
 *         <li> The shrinkable collection <b>{@code S}</b> now contains all singleton {@link Capability#BUNDLE_CAPABILITY 
73
 *         <li> The shrinkable collection <b>{@code S}</b> now contains all singleton {@link Capability#BUNDLE_CAPABILITY 
Lines 79-93 Link Here
79
 *       <ol type="a">
80
 *       <ol type="a">
80
 *         <li> For each requirement <b>{@code T}</b> specified by bundle revision <b>{@code B}</b> determine the 
81
 *         <li> For each requirement <b>{@code T}</b> specified by bundle revision <b>{@code B}</b> determine the 
81
 *              collection of capabilities that satisfy (or match) the requirement and place each matching capability into
82
 *              collection of capabilities that satisfy (or match) the requirement and place each matching capability into
82
 *              a shrinkable collection <b>{@code C}</b>.</li>
83
 *              a shrinkable collection <b>{@code C}</b>.  A capability is considered to match a particular requirement
83
 *         <li> For each registered hook call the {@link #filterMatches(BundleRevision, Collection)} with the
84
 *              if its attributes satisfy a specified requirement and the requirer bundle has permission to access the
85
 *              capability.</li>
86
 *         <li> For each resolver hook call the {@link #filterMatches(BundleRevision, Collection)} with the
84
 *              bundle revision <b>{@code B}</b> and the shrinkable collection <b>{@code C}</b>.</li>
87
 *              bundle revision <b>{@code B}</b> and the shrinkable collection <b>{@code C}</b>.</li>
85
 *         <li> The shrinkable collection <b>{@code C}</b> now contains all the capabilities that may be used to 
88
 *         <li> The shrinkable collection <b>{@code C}</b> now contains all the capabilities that may be used to 
86
 *              satisfy the requirement <b>{@code T}</b>.  Any other capabilities that got removed from the 
89
 *              satisfy the requirement <b>{@code T}</b>.  Any other capabilities that got removed from the 
87
 *              shrinkable collection <b>{@code C}</b> must not be used to satisfy requirement <b>{@code T}</b>.</li>
90
 *              shrinkable collection <b>{@code C}</b> must not be used to satisfy requirement <b>{@code T}</b>.</li>
88
 *       </ol>
91
 *       </ol>
89
 *  </li>
92
 *  </li>
90
 *  <li> For each registered hook call the {@link #end()} method to inform the hooks about a resolve 
93
 *  <li> For each resolver hook call the {@link #end()} method to inform the hooks about a resolve 
91
 *       process ending.</li>
94
 *       process ending.</li>
92
 * </ol>
95
 * </ol>
93
 * In all cases, the order in which the resolver hooks are called is the reverse compareTo ordering of 
96
 * In all cases, the order in which the resolver hooks are called is the reverse compareTo ordering of 
Lines 100-116 Link Here
100
 * resolve process (e.g. by calling {@link Bundle#start()} or {@link FrameworkWiring#resolveBundles(Collection)}).  
103
 * resolve process (e.g. by calling {@link Bundle#start()} or {@link FrameworkWiring#resolveBundles(Collection)}).  
101
 * The framework must detect this and throw an {@link IllegalStateException}.
104
 * The framework must detect this and throw an {@link IllegalStateException}.
102
 * 
105
 * 
106
 * @see ResolverHookFactory
103
 * @ThreadSafe
107
 * @ThreadSafe
104
 * @version $Id: 17fa0cb4223f6e2e6738ac675099d5aa8b44ab46 $
108
 * @version $Id: e896c443a68b3ea287735c9c19f0b1c62bd4755d $
105
 */
109
 */
106
public interface ResolverHook {
110
public interface ResolverHook {
107
108
	/**
109
	 * This method is called once at the beginning of the resolve process
110
	 * before any other methods are called on this hook.
111
	 */
112
	void begin();
113
114
	/**
111
	/**
115
	 * Filter resolvable candidates hook method.  This method may be called
112
	 * Filter resolvable candidates hook method.  This method may be called
116
	 * multiple times during a single resolve process.
113
	 * multiple times during a single resolve process.
Lines 158-163 Link Here
158
	 * <p>
155
	 * <p>
159
	 * All of the candidates will have the same name space and will 
156
	 * All of the candidates will have the same name space and will 
160
	 * match a requirement of the requirer.
157
	 * match a requirement of the requirer.
158
	 * <p>
159
	 * If the Java Runtime Environment supports permissions then the collection of 
160
	 * candidates will only contain candidates for which the requirer has permission to
161
	 * access.
161
	 * @param requirer the bundle revision which contains a requirement
162
	 * @param requirer the bundle revision which contains a requirement
162
	 * @param candidates a collection of candidates that match a requirement of the requirer
163
	 * @param candidates a collection of candidates that match a requirement of the requirer
163
	 */
164
	 */
Lines 166-174 Link Here
166
	/**
167
	/**
167
	 * This method is called once at the end of the resolve process.
168
	 * This method is called once at the end of the resolve process.
168
	 * After the end method is called the resolve process has ended.
169
	 * After the end method is called the resolve process has ended.
169
	 * No methods will be called on this hook except after the
170
	 * The framework must not hold onto this resolver hook instance
170
	 * {@link #begin() begin} method is called again to indicate
171
	 * after end has been called.
171
	 * a new resolve process is beginning.
172
	 */
172
	 */
173
	void end();
173
	void end();
174
}
174
}
(-)osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java (+83 lines)
Added Link Here
1
/*
2
 * Copyright (c) OSGi Alliance (2010). All Rights Reserved.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.osgi.framework.hooks.resolver;
18
19
import java.util.Collection;
20
21
import org.osgi.framework.Bundle;
22
import org.osgi.framework.wiring.BundleRevision;
23
import org.osgi.framework.wiring.FrameworkWiring;
24
25
/** 
26
 * OSGi Framework Resolver Hook Factory Service.
27
 * 
28
 * <p>
29
 * Bundles registering this service will be called by the framework during 
30
 * a bundle resolver process to obtain a {@link ResolverHook resolver hook}
31
 * instance which will be used for the duration of a resolve process.
32
 * 
33
 * @ThreadSafe
34
 * @see ResolverHook
35
 * @version $Id: 18ea1ec1f14f47410a43e99be4da3b2583149722 $
36
 */
37
public interface ResolverHookFactory {
38
	/**
39
	 * This method is called by the framework each time a resolve process begins
40
	 * to obtain a {@link ResolverHook resolver hook} instance.  This resolver hook 
41
	 * instance will be used for the duration of the resolve process.  At the end of 
42
	 * the resolve process the method {@link ResolverHook#end()} must be called by 
43
	 * the framework and the framework must not hold any references of the resolver 
44
	 * hook instance.
45
	 * <p>
46
	 * The triggers represent the collection of bundles which triggered
47
	 * the resolve process.  This collection may be empty if the triggers
48
	 * cannot be determined by the framework.  In most cases the triggers 
49
	 * can easily be determined.  Calling certain methods on 
50
	 * {@link Bundle bundle} when a bundle is in the {@link Bundle#INSTALLED INSTALLED} 
51
	 * state will cause the framework to begin a resolve process in order to resolve the 
52
	 * bundle.  The following methods will start a resolve process in this case:
53
	 * <ul>
54
	 *   <li>{@link Bundle#start() start}</li>
55
	 *   <li>{@link Bundle#loadClass(String) loadClass}</li>
56
	 *   <li>{@link Bundle#findEntries(String, String, boolean) findEntries}</li>
57
	 *   <li>{@link Bundle#getResource(String) getResource}</li>
58
	 *   <li>{@link Bundle#getResources(String) getResources}</li>
59
	 * </ul> 
60
	 * In such cases the collection will contain the single bundle which the
61
	 * framework is trying to resolve.  Other cases will cause multiple bundles to be
62
	 * included in the trigger bundles collection.  When {@link FrameworkWiring#resolveBundles(Collection)
63
	 * resolveBundles} is called the collection of triggers must include all the current bundle 
64
	 * revisions for bundles passed to resolveBundles which have not been uninstalled.
65
	 * <p>
66
	 * When {@link FrameworkWiring#refreshBundles(Collection, org.osgi.framework.FrameworkListener...)}
67
	 * is called the collection of triggers is determined with the following steps:
68
	 * <ul>
69
	 *   <li>If the collection of bundles passed is null then {@link FrameworkWiring#getRemovalPendingBundles()}
70
	 *   is called to get the initial collection of bundles.</li>
71
	 *   <li>The equivalent of calling {@link FrameworkWiring#getDependencyClosure(Collection)} is called with
72
	 *   the initial collection of bundles to get the dependency closure collection of the bundles being refreshed.</li>
73
	 *   <li>Remove any non-active bundles from the dependency closure collection.</li>
74
	 *   <li>For each bundle remaining in the dependency closure collection get the current bundle revision
75
	 *   and add it to the collection of triggers.</li> 
76
	 * </ul>
77
	 * @param triggers an unmodifiable collection of bundles which triggered the resolve process.
78
	 * This collection may be empty if the collection of trigger bundles cannot be
79
	 * determined.
80
	 * @return a resolver hook instance to be used for the duration of the resolve process.
81
	 */
82
	ResolverHook begin(Collection<BundleRevision> triggers);
83
}
(-)resolver/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java (-1 / +12 lines)
Lines 12-17 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.osgi.internal.resolver;
13
package org.eclipse.osgi.internal.resolver;
14
14
15
import java.util.Collection;
15
import java.util.Dictionary;
16
import java.util.Dictionary;
16
import org.eclipse.osgi.service.resolver.*;
17
import org.eclipse.osgi.service.resolver.*;
17
import org.osgi.framework.BundleException;
18
import org.osgi.framework.BundleException;
Lines 100-105 Link Here
100
		throw new UnsupportedOperationException();
101
		throw new UnsupportedOperationException();
101
	}
102
	}
102
103
104
	public StateDelta resolve(BundleDescription[] resolve, boolean discard) {
105
		throw new UnsupportedOperationException();
106
	}
107
108
	@SuppressWarnings("deprecation")
103
	public void setOverrides(Object value) {
109
	public void setOverrides(Object value) {
104
		throw new UnsupportedOperationException();
110
		throw new UnsupportedOperationException();
105
	}
111
	}
Lines 150-156 Link Here
150
		throw new UnsupportedOperationException();
156
		throw new UnsupportedOperationException();
151
	}
157
	}
152
158
153
	public Dictionary<Object, Object>[] getPlatformProperties() {
159
	@SuppressWarnings("rawtypes")
160
	public Dictionary[] getPlatformProperties() {
154
		return target.getPlatformProperties();
161
		return target.getPlatformProperties();
155
	}
162
	}
156
163
Lines 214-217 Link Here
214
		throw new UnsupportedOperationException();
221
		throw new UnsupportedOperationException();
215
	}
222
	}
216
223
224
	public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) {
225
		return target.getDependencyClosure(bundles);
226
	}
227
217
}
228
}
(-)resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java (-22 / +82 lines)
Lines 25-30 Link Here
25
import org.eclipse.osgi.util.NLS;
25
import org.eclipse.osgi.util.NLS;
26
import org.osgi.framework.*;
26
import org.osgi.framework.*;
27
import org.osgi.framework.hooks.resolver.ResolverHook;
27
import org.osgi.framework.hooks.resolver.ResolverHook;
28
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
29
import org.osgi.framework.wiring.BundleRevision;
28
30
29
public abstract class StateImpl implements State {
31
public abstract class StateImpl implements State {
30
	private static final String OSGI_OS = "osgi.os"; //$NON-NLS-1$
32
	private static final String OSGI_OS = "osgi.os"; //$NON-NLS-1$
Lines 54-59 Link Here
54
	private Dictionary<Object, Object>[] platformProperties = new Dictionary[] {new Hashtable<String, String>(PROPS.length)}; // Dictionary here because of Filter API
56
	private Dictionary<Object, Object>[] platformProperties = new Dictionary[] {new Hashtable<String, String>(PROPS.length)}; // Dictionary here because of Filter API
55
	private long highestBundleId = -1;
57
	private long highestBundleId = -1;
56
	private final Set<String> platformPropertyKeys = new HashSet<String>(PROPS.length);
58
	private final Set<String> platformPropertyKeys = new HashSet<String>(PROPS.length);
59
	private ResolverHookFactory hookFactory;
57
	private ResolverHook hook;
60
	private ResolverHook hook;
58
61
59
	private static long cumulativeTime;
62
	private static long cumulativeTime;
Lines 426-442 Link Here
426
		bundle.removeDependencies();
429
		bundle.removeDependencies();
427
	}
430
	}
428
431
429
	private StateDelta resolve(boolean incremental, BundleDescription[] reResolve) {
432
	private StateDelta resolve(boolean incremental, BundleDescription[] reResolve, BundleDescription[] triggers) {
430
		synchronized (this.monitor) {
433
		synchronized (this.monitor) {
431
			if (resolver == null)
434
			if (resolver == null)
432
				throw new IllegalStateException("no resolver set"); //$NON-NLS-1$
435
				throw new IllegalStateException("no resolver set"); //$NON-NLS-1$
433
			if (resolving == true)
436
			if (resolving == true)
434
				throw new IllegalStateException("An attempt to start a nested resolve process has been detected."); //$NON-NLS-1$
437
				throw new IllegalStateException("An attempt to start a nested resolve process has been detected."); //$NON-NLS-1$
435
			ResolverHook currentHook = getResolverHook();
438
			ResolverHook currentHook = null;
436
			try {
439
			try {
437
				resolving = true;
440
				resolving = true;
438
				if (currentHook != null)
439
					currentHook.begin();
440
				fullyLoad();
441
				fullyLoad();
441
				long start = 0;
442
				long start = 0;
442
				if (StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER)
443
				if (StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER)
Lines 450-461 Link Here
450
						reResolve = mergeBundles(reResolve, removed);
451
						reResolve = mergeBundles(reResolve, removed);
451
					}
452
					}
452
					flush(reResolve);
453
					flush(reResolve);
453
				}
454
				} else {
454
				if (resolved && reResolve == null)
455
					if (resolved && reResolve == null)
455
					return new StateDeltaImpl(this);
456
						return new StateDeltaImpl(this);
456
				if (removalPendings.size() > 0) {
457
					if (reResolve == null)
457
					BundleDescription[] removed = internalGetRemovalPending();
458
						reResolve = internalGetRemovalPending();
458
					reResolve = mergeBundles(reResolve, removed);
459
					if (triggers == null) {
460
						Set<BundleDescription> triggerSet = new HashSet<BundleDescription>();
461
						Collection<BundleDescription> closure = getDependencyClosure(Arrays.asList(reResolve));
462
						for (BundleDescription toRefresh : closure) {
463
							Bundle bundle = toRefresh.getBundle();
464
							if (bundle != null && (bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED | Bundle.RESOLVED)) == 0)
465
								triggerSet.add(toRefresh);
466
						}
467
						triggers = triggerSet.toArray(new BundleDescription[triggerSet.size()]);
468
					}
459
				}
469
				}
460
				// use the Headers class to handle ignoring case while matching keys (bug 180817)
470
				// use the Headers class to handle ignoring case while matching keys (bug 180817)
461
				@SuppressWarnings("unchecked")
471
				@SuppressWarnings("unchecked")
Lines 467-472 Link Here
467
						tmpPlatformProperties[i].put(key, platformProperties[i].get(key));
477
						tmpPlatformProperties[i].put(key, platformProperties[i].get(key));
468
					}
478
					}
469
				}
479
				}
480
481
				ResolverHookFactory currentFactory = hookFactory;
482
				if (currentFactory != null) {
483
					@SuppressWarnings("unchecked")
484
					Collection<BundleRevision> triggerRevisions = Collections.unmodifiableCollection(triggers == null ? Collections.EMPTY_LIST : Arrays.asList((BundleRevision[]) triggers));
485
					currentHook = begin(triggerRevisions);
486
				}
470
				resolver.resolve(reResolve, tmpPlatformProperties);
487
				resolver.resolve(reResolve, tmpPlatformProperties);
471
				resolved = removalPendings.size() == 0;
488
				resolved = removalPendings.size() == 0;
472
489
Lines 526-550 Link Here
526
	}
543
	}
527
544
528
	public StateDelta resolve() {
545
	public StateDelta resolve() {
529
		return resolve(true, null);
546
		return resolve(true, null, null);
530
	}
547
	}
531
548
532
	public StateDelta resolve(boolean incremental) {
549
	public StateDelta resolve(boolean incremental) {
533
		return resolve(incremental, null);
550
		return resolve(incremental, null, null);
534
	}
551
	}
535
552
536
	public StateDelta resolve(BundleDescription[] reResolve) {
553
	public StateDelta resolve(BundleDescription[] reResolve) {
537
		return resolve(true, reResolve);
554
		return resolve(true, reResolve, null);
538
	}
555
	}
539
556
557
	public StateDelta resolve(BundleDescription[] resolve, boolean discard) {
558
		BundleDescription[] reResolve = discard ? resolve : new BundleDescription[0];
559
		BundleDescription[] triggers = discard ? null : resolve;
560
		return resolve(true, reResolve, triggers);
561
	}
562
563
	@SuppressWarnings("deprecation")
540
	public void setOverrides(Object value) {
564
	public void setOverrides(Object value) {
541
		throw new UnsupportedOperationException();
565
		throw new UnsupportedOperationException();
542
	}
566
	}
543
567
544
	public void setResolverHook(ResolverHook hook) {
568
	public void setResolverHookFactory(ResolverHookFactory hookFactory) {
569
		synchronized (this.monitor) {
570
			this.hookFactory = hookFactory;
571
		}
572
	}
573
574
	private ResolverHook begin(Collection<BundleRevision> triggers) {
575
		ResolverHookFactory current;
576
		synchronized (this.monitor) {
577
			current = this.hookFactory;
578
		}
579
		ResolverHook newHook = current.begin(triggers);
545
		synchronized (this.monitor) {
580
		synchronized (this.monitor) {
546
			this.hook = hook;
581
			this.hook = newHook;
547
		}
582
		}
583
		return newHook;
548
	}
584
	}
549
585
550
	public ResolverHook getResolverHook() {
586
	public ResolverHook getResolverHook() {
Lines 874-883 Link Here
874
		return symbolicName != null ? symbolicName : Constants.getInternalSymbolicName();
910
		return symbolicName != null ? symbolicName : Constants.getInternalSymbolicName();
875
	}
911
	}
876
912
877
	/**
878
	 * Returns the latest versions BundleDescriptions which have old removal pending versions.
879
	 * @return the BundleDescriptions that have removal pending versions.
880
	 */
881
	public BundleDescription[] getRemovalPending() {
913
	public BundleDescription[] getRemovalPending() {
882
		synchronized (this.monitor) {
914
		synchronized (this.monitor) {
883
			return removalPendings.toArray(new BundleDescription[removalPendings.size()]);
915
			return removalPendings.toArray(new BundleDescription[removalPendings.size()]);
Lines 891-896 Link Here
891
		}
923
		}
892
	}
924
	}
893
925
926
	public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) {
927
		BundleDescription[] removals = getRemovalPending();
928
		Set<BundleDescription> result = new HashSet<BundleDescription>();
929
		for (BundleDescription bundle : bundles) {
930
			addDependents(bundle, result, removals);
931
		}
932
		return result;
933
	}
934
935
	private static void addDependents(BundleDescription bundle, Set<BundleDescription> result, BundleDescription[] removals) {
936
		if (result.contains(bundle))
937
			return; // avoid cycles
938
		result.add(bundle);
939
		BundleDescription[] dependents = bundle.getDependents();
940
		for (BundleDescription dependent : dependents)
941
			addDependents(dependent, result, removals);
942
		// check if this is a removal pending
943
		for (BundleDescription removed : removals) {
944
			if (removed.getBundleId() == bundle.getBundleId())
945
				addDependents(removed, result, removals);
946
		}
947
	}
948
894
	/**
949
	/**
895
	 * Returns the latest versions BundleDescriptions which have old removal pending versions.
950
	 * Returns the latest versions BundleDescriptions which have old removal pending versions.
896
	 * @return the BundleDescriptions that have removal pending versions.
951
	 * @return the BundleDescriptions that have removal pending versions.
Lines 915-925 Link Here
915
			return null;
970
			return null;
916
		fullyLoad();
971
		fullyLoad();
917
		synchronized (this.monitor) {
972
		synchronized (this.monitor) {
918
			ResolverHook currentHook = getResolverHook();
973
			ResolverHook currentHook = null;
919
			try {
974
			try {
920
				resolving = true;
975
				resolving = true;
921
				if (currentHook != null)
976
				ResolverHookFactory currentFactory = hookFactory;
922
					currentHook.begin();
977
				if (currentFactory != null) {
978
					Collection<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
979
					triggers.add(importingBundle);
980
					triggers = Collections.unmodifiableCollection(triggers);
981
					currentHook = begin(triggers);
982
				}
923
				// ask the resolver to resolve our dynamic import
983
				// ask the resolver to resolve our dynamic import
924
				ExportPackageDescriptionImpl result = (ExportPackageDescriptionImpl) resolver.resolveDynamicImport(importingBundle, requestedPackage);
984
				ExportPackageDescriptionImpl result = (ExportPackageDescriptionImpl) resolver.resolveDynamicImport(importingBundle, requestedPackage);
925
				if (result == null)
985
				if (result == null)

Return to bug 326011