Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 9d3ef6240aead0952b5a47b793780c1c0589089a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
 * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osgi.framework.hooks.resolver;

import java.util.Collection;
import org.osgi.framework.Bundle;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.FrameworkWiring;

/**
 * OSGi Framework Resolver Hook instances are obtained from the OSGi
 * {@link ResolverHookFactory Framework Resolver Hook Factory} service.
 * 
 * <p>
 * A Resolver Hook instance is called by the framework during a resolve process.
 * A resolver hook may influence the outcome of a resolve process by removing
 * entries from shrinkable collections that are passed to the hook during a
 * resolve process. A shrinkable collection is a {@code Collection} that
 * supports all remove operations. Any other attempts to modify a shrinkable
 * collection will result in an {@code UnsupportedOperationException} being
 * thrown.
 * 
 * <p>
 * The following steps outline the way a framework uses the resolver hooks
 * during a resolve process.
 * <ol>
 * <li>Collect a snapshot of registered resolver hook factories that will be
 * called during the current resolve process. Any hook factories registered
 * after the snapshot is taken must not be called during the current resolve
 * process. A resolver hook factory contained in the snapshot may become
 * unregistered during the resolve process. The framework should handle this and
 * stop calling the resolver hook instance provided by the unregistered hook
 * factory and the current resolve process must fail. If possible, an exception
 * must be thrown to the caller of the API which triggered the resolve process.
 * In cases where the the caller is not available a framework event of type
 * error should be fired.</li>
 * 
 * <li>For each registered hook factory call the
 * {@link ResolverHookFactory#begin(Collection)} method to inform the hooks
 * about a resolve process beginning and to obtain a Resolver Hook instance that
 * will be used for the duration of the resolve process.</li>
 * 
 * <li>Determine the collection of unresolved bundle revisions that may be
 * considered for resolution during the current resolution process and place
 * each of the bundle revisions in a shrinkable collection {@code Resolvable}.
 * For each resolver hook call the {@link #filterResolvable(Collection)} method
 * with the shrinkable collection {@code Resolvable}.</li>
 * <li>The shrinkable collection {@code Resolvable} now contains all the
 * unresolved bundle revisions that may end up as resolved at the end of the
 * current resolve process. Any other bundle revisions that got removed from the
 * shrinkable collection {@code Resolvable} must not end up as resolved at the
 * end of the current resolve process.</li>
 * <li>For each bundle revision {@code B} left in the shrinkable collection
 * {@code Resolvable} and any bundle revision {@code B} which is currently
 * resolved that represents a singleton bundle do the following:
 * <p/>
 * Determine the collection of available capabilities that have a namespace of
 * {@link IdentityNamespace osgi.identity}, are singletons, and have the same
 * symbolic name as the singleton bundle revision {@code B} and place each of
 * the matching capabilities into a shrinkable collection {@code Collisions}.
 * <p/>
 * Remove the {@link IdentityNamespace osgi.identity} capability provided by
 * bundle revision {@code B} from shrinkable collection {@code Collisions}. A
 * singleton bundle cannot collide with itself.
 * <p/>
 * For each resolver hook call the
 * {@link #filterSingletonCollisions(BundleCapability, Collection)} with the
 * {@link IdentityNamespace osgi.identity} capability provided by bundle
 * revision {@code B} and the shrinkable collection {@code Collisions}
 * <p/>
 * The shrinkable collection {@code Collisions} now contains all singleton
 * {@link IdentityNamespace osgi.identity} capabilities that can influence the
 * ability of bundle revision {@code B} to resolve.
 * <p/>
 * If the bundle revision {@code B} is already resolved then any resolvable
 * bundle revision contained in the collection {@code Collisions} is not allowed
 * to resolve.</li>
 * <li>During a resolve process a framework is free to attempt to resolve any or
 * all bundles contained in shrinkable collection {@code Resolvable}. For each
 * bundle revision {@code B} left in the shrinkable collection
 * {@code Resolvable} which the framework attempts to resolve the following
 * steps must be followed:
 * <p/>
 * For each requirement {@code R} specified by bundle revision {@code B}
 * determine the collection of capabilities that satisfy (or match) the
 * requirement and place each matching capability into a shrinkable collection
 * {@code Candidates}. A capability is considered to match a particular
 * requirement if its attributes satisfy a specified requirement and the
 * requirer bundle has permission to access the capability.
 * 
 * <p/>
 * For each resolver hook call the
 * {@link #filterMatches(BundleRequirement, Collection)} with the requirement
 * {@code R} and the shrinkable collection {@code Candidates}.
 * 
 * <p/>
 * The shrinkable collection {@code Candidates} now contains all the
 * capabilities that may be used to satisfy the requirement {@code R}. Any other
 * capabilities that got removed from the shrinkable collection
 * {@code Candidates} must not be used to satisfy requirement {@code R}.</li>
 * <li>For each resolver hook call the {@link #end()} method to inform the hooks
 * about a resolve process ending.</li>
 * </ol>
 * In all cases, the order in which the resolver hooks are called is the reverse
 * compareTo ordering of their Service References. That is, the service with the
 * highest ranking number must be called first. In cases where a shrinkable
 * collection becomes empty the framework is required to call the remaining
 * registered hooks.
 * <p>
 * Resolver hooks are low level. Implementations of the resolver hook must be
 * careful not to create an unresolvable state which is very hard for a
 * developer or a provisioner to diagnose. Resolver hooks also must not be
 * allowed to start another synchronous resolve process (e.g. by calling
 * {@link Bundle#start()} or {@link FrameworkWiring#resolveBundles(Collection)}
 * ). The framework must detect this and throw an {@link IllegalStateException}.
 * 
 * @see ResolverHookFactory
 * @NotThreadSafe
 * @version $Id$
 */
public interface ResolverHook {
	/**
	 * Filter resolvable candidates hook method. This method may be called
	 * multiple times during a single resolve process. This method can filter
	 * the collection of candidates by removing potential candidates. Removing a
	 * candidate will prevent the candidate from resolving during the current
	 * resolve process.
	 * 
	 * @param candidates the collection of resolvable candidates available
	 *        during a resolve process.
	 */
	void filterResolvable(Collection<BundleRevision> candidates);

	/**
	 * Filter singleton collisions hook method. This method is called during the
	 * resolve process for the specified singleton. The specified singleton
	 * represents a singleton capability and the specified collection represent
	 * a collection of singleton capabilities which are considered collision
	 * candidates. The singleton capability and the collection of collision
	 * candidates must all use the same namespace.
	 * <p>
	 * Currently only capabilities with the namespace of {@link BundleNamespace
	 * osgi.wiring.bundle} and {@link IdentityNamespace osgi.identity} can be
	 * singletons. The collision candidates will all have the same namespace, be
	 * singletons, and have the same symbolic name as the specified singleton
	 * capability.
	 * <p>
	 * In the future, capabilities in other namespaces may support the singleton
	 * concept. Hook implementations should be prepared to receive calls to this
	 * method for capabilities in namespaces other than {@link BundleNamespace
	 * osgi.wiring.bundle} or {@link IdentityNamespace osgi.identity}.
	 * <p>
	 * This method can filter the list of collision candidates by removing
	 * potential collisions. Removing a collision candidate will allow the
	 * specified singleton to resolve regardless of the resolution state of the
	 * removed collision candidate.
	 * 
	 * @param singleton the singleton involved in a resolve process
	 * @param collisionCandidates a collection of singleton collision candidates
	 */
	void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates);

	/**
	 * Filter matches hook method. This method is called during the resolve
	 * process for the specified requirement. The collection of candidates match
	 * the specified requirement. This method can filter the collection of
	 * matching candidates by removing candidates from the collection. Removing
	 * a candidate will prevent the resolve process from choosing the removed
	 * candidate to satisfy the requirement.
	 * <p>
	 * All of the candidates will have the same namespace and will match the
	 * specified requirement.
	 * <p>
	 * If the Java Runtime Environment supports permissions then the collection
	 * of candidates will only contain candidates for which the requirer has
	 * permission to access.
	 * 
	 * @param requirement the requirement to filter candidates for
	 * @param candidates a collection of candidates that match the requirement
	 */
	void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates);

	/**
	 * This method is called once at the end of the resolve process. After the
	 * end method is called the resolve process has ended. The framework must
	 * not hold onto this resolver hook instance after end has been called.
	 */
	void end();
}

Back to the top