KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > internal > resolver > StateHelperImpl


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 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.internal.resolver;
12
13 import java.util.*;
14
15 import org.eclipse.osgi.framework.internal.core.Constants;
16 import org.eclipse.osgi.service.resolver.*;
17
18 /**
19  * An implementation for the StateHelper API. Access to this implementation is
20  * provided by the PlatformAdmin. Since this helper is a general facility for
21  * state manipulation, it should not be tied to any implementation details.
22  */

23 public class StateHelperImpl implements StateHelper {
24     private static StateHelper instance = new StateHelperImpl();
25
26     /**
27      * @see StateHelper
28      */

29     public BundleDescription[] getDependentBundles(BundleDescription[] bundles) {
30         if (bundles == null || bundles.length == 0)
31             return new BundleDescription[0];
32
33         Set reachable = new HashSet(bundles.length);
34         for (int i = 0; i < bundles.length; i++) {
35             if (!bundles[i].isResolved())
36                 continue;
37             addDependentBundles(bundles[i], reachable);
38         }
39         return (BundleDescription[]) reachable.toArray(new BundleDescription[reachable.size()]);
40     }
41
42     private void addDependentBundles(BundleDescription bundle, Set reachable) {
43         if (reachable.contains(bundle))
44             return;
45         reachable.add(bundle);
46         BundleDescription[] dependents = bundle.getDependents();
47         for (int i = 0; i < dependents.length; i++)
48             addDependentBundles(dependents[i], reachable);
49     }
50
51     public BundleDescription[] getPrerequisites(BundleDescription[] bundles) {
52         if (bundles == null || bundles.length == 0)
53             return new BundleDescription[0];
54         Set reachable = new HashSet(bundles.length);
55         for (int i = 0; i < bundles.length; i++)
56             addPrerequisites(bundles[i], reachable);
57         return (BundleDescription[]) reachable.toArray(new BundleDescription[reachable.size()]);
58     }
59
60     private void addPrerequisites(BundleDescription bundle, Set reachable) {
61         if (reachable.contains(bundle))
62             return;
63         reachable.add(bundle);
64         List depList = ((BundleDescriptionImpl) bundle).getBundleDependencies();
65         BundleDescription[] dependencies = (BundleDescription[]) depList.toArray(new BundleDescription[depList.size()]);
66         for (int i = 0; i < dependencies.length; i++)
67             addPrerequisites(dependencies[i], reachable);
68     }
69
70     private Map getExportedPackageMap(State state) {
71         Map result = new HashMap(11);
72         BundleDescription[] bundles = state.getBundles();
73         for (int i = 0; i < bundles.length; i++) {
74             ExportPackageDescription[] packages = bundles[i].getExportPackages();
75             for (int j = 0; j < packages.length; j++) {
76                 ExportPackageDescription description = packages[j];
77                 Set exports = (Set) result.get(description.getName());
78                 if (exports == null) {
79                     exports = new HashSet(1);
80                     result.put(description.getName(), exports);
81                 }
82                 exports.add(description);
83             }
84         }
85         return result;
86     }
87
88     private Map getGenericsMap(State state, boolean resolved) {
89         Map result = new HashMap(11);
90         BundleDescription[] bundles = state.getBundles();
91         for (int i = 0; i < bundles.length; i++) {
92             if (resolved && !bundles[i].isResolved())
93                 continue; // discard unresolved bundles
94
GenericDescription[] generics = bundles[i].getGenericCapabilities();
95             for (int j = 0; j < generics.length; j++) {
96                 GenericDescription description = generics[j];
97                 Set genericSet = (Set) result.get(description.getName());
98                 if (genericSet == null) {
99                     genericSet = new HashSet(1);
100                     result.put(description.getName(), genericSet);
101                 }
102                 genericSet.add(description);
103             }
104         }
105         return result;
106     }
107
108     private VersionConstraint[] getUnsatisfiedLeaves(State state, BundleDescription[] bundles) {
109         Map packages = getExportedPackageMap(state);
110         Map generics = getGenericsMap(state, false);
111         HashSet result = new HashSet(11);
112         for (int i = 0; i < bundles.length; i++) {
113             BundleDescription description = bundles[i];
114             VersionConstraint[] constraints = getUnsatisfiedConstraints(description);
115             for (int j = 0; j < constraints.length; j++) {
116                 VersionConstraint constraint = constraints[j];
117                 boolean satisfied = false;
118                 if (constraint instanceof BundleSpecification || constraint instanceof HostSpecification) {
119                     BundleDescription[] suppliers = state.getBundles(constraint.getName());
120                     for (int k = 0; k < suppliers.length && !satisfied; k++)
121                         satisfied |= constraint.isSatisfiedBy(suppliers[k]);
122                 } else if (constraint instanceof ImportPackageSpecification) {
123                     Set exports = (Set) packages.get(constraint.getName());
124                     if (exports != null)
125                         for (Iterator iter = exports.iterator(); iter.hasNext() && !satisfied;)
126                             satisfied |= constraint.isSatisfiedBy((ExportPackageDescription) iter.next());
127                 } else if (constraint instanceof GenericSpecification) {
128                     Set genericSet = (Set) generics.get(constraint.getName());
129                     if (genericSet != null)
130                         for (Iterator iter = genericSet.iterator(); iter.hasNext() && !satisfied;)
131                             satisfied |= constraint.isSatisfiedBy((GenericDescription) iter.next());
132                 }
133                 if (!satisfied)
134                     result.add(constraint);
135             }
136         }
137         return (VersionConstraint[]) result.toArray(new VersionConstraint[result.size()]);
138
139     }
140
141     public VersionConstraint[] getUnsatisfiedLeaves(BundleDescription[] bundles) {
142         if (bundles.length == 0)
143             return new VersionConstraint[0];
144         State state = bundles[0].getContainingState();
145         return getUnsatisfiedLeaves(state, bundles);
146     }
147
148     /**
149      * @see StateHelper
150      */

151     public VersionConstraint[] getUnsatisfiedConstraints(BundleDescription bundle) {
152         State containingState = bundle.getContainingState();
153         if (containingState == null)
154             // it is a bug in the client to call this method when not attached to a state
155
throw new IllegalStateException JavaDoc("Does not belong to a state"); //$NON-NLS-1$
156
List unsatisfied = new ArrayList();
157         HostSpecification host = bundle.getHost();
158         if (host != null)
159             if (!host.isResolved() && !isResolvable(host))
160                 unsatisfied.add(host);
161         BundleSpecification[] requiredBundles = bundle.getRequiredBundles();
162         for (int i = 0; i < requiredBundles.length; i++)
163             if (!requiredBundles[i].isResolved() && !isResolvable(requiredBundles[i]))
164                 unsatisfied.add(requiredBundles[i]);
165         ImportPackageSpecification[] packages = bundle.getImportPackages();
166         for (int i = 0; i < packages.length; i++)
167             if (!packages[i].isResolved() && !isResolvable(packages[i]))
168                 unsatisfied.add(packages[i]);
169         GenericSpecification[] generics = bundle.getGenericRequires();
170         for (int i = 0; i < generics.length; i++)
171             if (!generics[i].isResolved() && !isResolvable(generics[i]))
172                 unsatisfied.add(generics[i]);
173         return (VersionConstraint[]) unsatisfied.toArray(new VersionConstraint[unsatisfied.size()]);
174     }
175
176     /**
177      * @see StateHelper
178      */

179     public boolean isResolvable(ImportPackageSpecification constraint) {
180         ExportPackageDescription[] exports = constraint.getBundle().getContainingState().getExportedPackages();
181         for (int i = 0; i < exports.length; i++)
182             if (constraint.isSatisfiedBy(exports[i]))
183                 return true;
184         return false;
185     }
186
187     private boolean isResolvable(GenericSpecification constraint) {
188         Map genericCapabilities = getGenericsMap(constraint.getBundle().getContainingState(), true);
189         Set genericSet = (Set) genericCapabilities.get(constraint.getName());
190         if (genericSet == null)
191             return false;
192         for (Iterator iter = genericSet.iterator(); iter.hasNext();)
193             if (constraint.isSatisfiedBy((GenericDescription) iter.next()))
194                 return true;
195         return false;
196     }
197
198     /**
199      * @see StateHelper
200      */

201     public boolean isResolvable(BundleSpecification specification) {
202         return isBundleConstraintResolvable(specification);
203     }
204
205     /**
206      * @see StateHelper
207      */

208     public boolean isResolvable(HostSpecification specification) {
209         return isBundleConstraintResolvable(specification);
210     }
211
212     /*
213      * Returns whether a bundle specification/host specification can be resolved.
214      */

215     private boolean isBundleConstraintResolvable(VersionConstraint constraint) {
216         BundleDescription[] availableBundles = constraint.getBundle().getContainingState().getBundles(constraint.getName());
217         for (int i = 0; i < availableBundles.length; i++)
218             if (availableBundles[i].isResolved() && constraint.isSatisfiedBy(availableBundles[i]))
219                 return true;
220         return false;
221     }
222
223     public Object JavaDoc[][] sortBundles(BundleDescription[] toSort) {
224         List references = new ArrayList(toSort.length);
225         for (int i = 0; i < toSort.length; i++)
226             if (toSort[i].isResolved())
227                 buildReferences(toSort[i], references);
228         return ComputeNodeOrder.computeNodeOrder(toSort, (Object JavaDoc[][]) references.toArray(new Object JavaDoc[references.size()][]));
229     }
230
231     private void buildReferences(BundleDescription description, List references) {
232         HostSpecification host = description.getHost();
233         // it is a fragment
234
if (host != null) {
235             // just create a dependency between fragment and host
236
if (host.getHosts() != null) {
237                 BundleDescription[] hosts = host.getHosts();
238                 for (int i = 0; i < hosts.length; i++)
239                     if (hosts[i] != description)
240                         references.add(new Object JavaDoc[] {description, hosts[i]});
241             }
242         } else {
243             // it is a host
244
buildReferences(description, ((BundleDescriptionImpl) description).getBundleDependencies(), references);
245         }
246     }
247
248     private void buildReferences(BundleDescription description, List dependencies, List references) {
249         for (Iterator iter = dependencies.iterator(); iter.hasNext();)
250             addReference(description, (BundleDescription) iter.next(), references);
251     }
252
253     private void addReference(BundleDescription description, BundleDescription reference, List references) {
254         // build the reference from the description
255
if (description == reference || reference == null)
256             return;
257         BundleDescription[] fragments = reference.getFragments();
258         for (int i = 0; i < fragments.length; i++) {
259             if (fragments[i].isResolved()) {
260                 ExportPackageDescription[] exports = fragments[i].getExportPackages();
261                 if (exports.length > 0)
262                     references.add(new Object JavaDoc[] {description, fragments[i]});
263             }
264         }
265         references.add(new Object JavaDoc[] {description, reference});
266     }
267
268     public ExportPackageDescription[] getVisiblePackages(BundleDescription bundle) {
269         return getVisiblePackages(bundle, 0);
270     }
271
272     public ExportPackageDescription[] getVisiblePackages(BundleDescription bundle, int options) {
273         StateImpl state = (StateImpl) bundle.getContainingState();
274         boolean strict = false;
275         if (state != null)
276             strict = state.inStrictMode();
277         ArrayList orderedPkgList = new ArrayList(); // list of all ExportPackageDescriptions that are visible (ArrayList is used to keep order)
278
Set pkgSet = new HashSet();
279         Set importList = new HashSet(); // list of package names which are directly imported
280
// get the list of directly imported packages first.
281
ImportPackageSpecification[] imports = bundle.getImportPackages();
282         for (int i = 0; i < imports.length; i++) {
283             ExportPackageDescription pkgSupplier = (ExportPackageDescription) imports[i].getSupplier();
284             if (pkgSupplier == null)
285                 continue;
286             if (!isSystemExport(pkgSupplier, options) && !pkgSet.contains(pkgSupplier)) {
287                 orderedPkgList.add(pkgSupplier);
288                 pkgSet.add(pkgSupplier);
289             }
290             // get the sources of the required bundles of the exporter
291
BundleSpecification[] requires = pkgSupplier.getExporter().getRequiredBundles();
292             Set visited = new HashSet();
293             visited.add(bundle); // always add self to prevent recursing into self
294
Set importNames = new HashSet(1);
295             importNames.add(imports[i].getName());
296             for (int j = 0; j < requires.length; j++) {
297                 BundleDescription bundleSupplier = (BundleDescription) requires[j].getSupplier();
298                 if (bundleSupplier != null)
299                     getPackages(bundleSupplier, bundle.getSymbolicName(), importList, orderedPkgList, pkgSet, visited, strict, importNames, options);
300             }
301             importList.add(imports[i].getName()); // besure to add to direct import list
302
}
303         // now find all the packages that are visible from required bundles
304
BundleSpecification[] requires = bundle.getRequiredBundles();
305         Set visited = new HashSet(requires.length);
306         visited.add(bundle); // always add self to prevent recursing into self
307
for (int i = 0; i < requires.length; i++) {
308             BundleDescription bundleSupplier = (BundleDescription) requires[i].getSupplier();
309             if (bundleSupplier != null)
310                 getPackages(bundleSupplier, bundle.getSymbolicName(), importList, orderedPkgList, pkgSet, visited, strict, null, options);
311         }
312         return (ExportPackageDescription[]) orderedPkgList.toArray(new ExportPackageDescription[orderedPkgList.size()]);
313     }
314
315     private void getPackages(BundleDescription requiredBundle, String JavaDoc symbolicName, Set importList, ArrayList orderedPkgList, Set pkgSet, Set visited, boolean strict, Set pkgNames, int options) {
316         if (visited.contains(requiredBundle))
317             return; // prevent duplicate entries and infinate loops incase of cycles
318
visited.add(requiredBundle);
319         // add all the exported packages from the required bundle; take x-friends into account.
320
ExportPackageDescription[] exports = requiredBundle.getSelectedExports();
321         HashSet exportNames = new HashSet(exports.length); // set is used to improve performance of duplicate check.
322
for (int i = 0; i < exports.length; i++)
323             if ((pkgNames == null || pkgNames.contains(exports[i].getName())) && !isSystemExport(exports[i], options) && isFriend(symbolicName, exports[i], strict) && !importList.contains(exports[i].getName()) && !pkgSet.contains(exports[i])) {
324                 if (!exportNames.contains(exports[i].getName())) {
325                     // only add the first export
326
orderedPkgList.add(exports[i]);
327                     pkgSet.add(exports[i]);
328                     exportNames.add(exports[i].getName());
329                 }
330             }
331         // now look for exports from the required bundle.
332
BundleSpecification[] requiredBundles = requiredBundle.getRequiredBundles();
333         for (int i = 0; i < requiredBundles.length; i++) {
334             if (requiredBundles[i].getSupplier() == null)
335                 continue;
336             if (requiredBundles[i].isExported()) {
337                 // looking for a specific package and that package is exported by this bundle or adding all packages from a reexported bundle
338
getPackages((BundleDescription) requiredBundles[i].getSupplier(), symbolicName, importList, orderedPkgList, pkgSet, visited, strict, pkgNames, options);
339             } else if (exportNames.size() > 0) {
340                 // adding any exports from required bundles which we also export
341
Set tmpVisited = new HashSet();
342                 getPackages((BundleDescription) requiredBundles[i].getSupplier(), symbolicName, importList, orderedPkgList, pkgSet, tmpVisited, strict, exportNames, options);
343             }
344         }
345     }
346
347     private boolean isSystemExport(ExportPackageDescription export, int options) {
348         if ((options & VISIBLE_INCLUDE_EE_PACKAGES) != 0)
349             return false;
350         return ((Integer JavaDoc) export.getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue() >= 0;
351     }
352
353     private boolean isFriend(String JavaDoc consumerBSN, ExportPackageDescription export, boolean strict) {
354         if (!strict)
355             return true; // ignore friends rules if not in strict mode
356
String JavaDoc[] friends = (String JavaDoc[]) export.getDirective(Constants.FRIENDS_DIRECTIVE);
357         if (friends == null)
358             return true; // no x-friends means it is wide open
359
for (int i = 0; i < friends.length; i++)
360             if (friends[i].equals(consumerBSN))
361                 return true; // the consumer is a friend
362
return false;
363     }
364
365     public int getAccessCode(BundleDescription bundle, ExportPackageDescription export) {
366         if (((Boolean JavaDoc) export.getDirective(Constants.INTERNAL_DIRECTIVE)).booleanValue())
367             return ACCESS_DISCOURAGED;
368         if (!isFriend(bundle.getSymbolicName(), export, true)) // pass strict here so that x-friends is processed
369
return ACCESS_DISCOURAGED;
370         return ACCESS_ENCOURAGED;
371     }
372
373     public static StateHelper getInstance() {
374         return instance;
375     }
376 }
377
Popular Tags