KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > internal > module > ResolverBundle


1 /*******************************************************************************
2  * Copyright (c) 2004, 2007 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.module;
12
13 import java.util.*;
14 import org.eclipse.osgi.internal.resolver.ExportPackageDescriptionImpl;
15 import org.eclipse.osgi.service.resolver.*;
16 import org.osgi.framework.Constants;
17
18 /*
19  * A companion to BundleDescription from the state used while resolving.
20  */

21 public class ResolverBundle extends VersionSupplier implements Comparable JavaDoc{
22     public static final int UNRESOLVED = 0;
23     public static final int RESOLVING = 1;
24     public static final int RESOLVED = 2;
25
26     private Long JavaDoc bundleID;
27     private BundleConstraint host;
28     private ResolverImport[] imports;
29     private ResolverExport[] exports;
30     private BundleConstraint[] requires;
31     private GenericCapability[] capabilities;
32     private GenericConstraint[] genericReqiures;
33     // Fragment support
34
private ArrayList fragments;
35     private HashMap fragmentExports;
36     private HashMap fragmentImports;
37     private HashMap fragmentRequires;
38     private HashMap fragmentGenericRequires;
39     // Flag specifying whether this bundle is resolvable
40
private boolean resolvable = true;
41     // Internal resolver state for this bundle
42
private int state = UNRESOLVED;
43
44     private ResolverImpl resolver;
45     private boolean newFragmentExports;
46     private ArrayList refs;
47
48     ResolverBundle(BundleDescription bundle, ResolverImpl resolver) {
49         super(bundle);
50         this.bundleID = new Long JavaDoc(bundle.getBundleId());
51         this.resolver = resolver;
52         initialize(bundle.isResolved());
53     }
54
55     void initialize(boolean useSelectedExports) {
56         if (getBundle().isSingleton())
57             refs = new ArrayList();
58         // always add generic capabilities
59
GenericDescription[] actualCapabilities = getBundle().getGenericCapabilities();
60         capabilities = new GenericCapability[actualCapabilities.length];
61         for (int i = 0; i < capabilities.length; i++)
62             capabilities[i] = new GenericCapability(this, actualCapabilities[i]);
63         if (getBundle().getHost() != null) {
64             host = new BundleConstraint(this, getBundle().getHost());
65             exports = new ResolverExport[0];
66             imports = new ResolverImport[0];
67             requires = new BundleConstraint[0];
68             genericReqiures = new GenericConstraint[0];
69             return;
70         }
71
72         ImportPackageSpecification[] actualImports = getBundle().getImportPackages();
73         // Reorder imports so that optionals are at the end so that we wire statics before optionals
74
ArrayList importList = new ArrayList(actualImports.length);
75         for (int i = actualImports.length - 1; i >= 0; i--)
76             if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(actualImports[i].getDirective(Constants.RESOLUTION_DIRECTIVE)))
77                 importList.add(new ResolverImport(this, actualImports[i]));
78             else
79                 importList.add(0, new ResolverImport(this, actualImports[i]));
80         imports = (ResolverImport[]) importList.toArray(new ResolverImport[importList.size()]);
81
82         ExportPackageDescription[] actualExports = useSelectedExports ? getBundle().getSelectedExports() : getBundle().getExportPackages();
83         exports = new ResolverExport[actualExports.length];
84         for (int i = 0; i < actualExports.length; i++)
85             exports[i] = new ResolverExport(this, actualExports[i]);
86
87         BundleSpecification[] actualRequires = getBundle().getRequiredBundles();
88         requires = new BundleConstraint[actualRequires.length];
89         for (int i = 0; i < requires.length; i++)
90             requires[i] = new BundleConstraint(this, actualRequires[i]);
91
92         GenericSpecification[] actualGenericRequires = getBundle().getGenericRequires();
93         genericReqiures = new GenericConstraint[actualGenericRequires.length];
94         for (int i = 0; i < genericReqiures.length; i++)
95             genericReqiures[i] = new GenericConstraint(this, actualGenericRequires[i]);
96
97         fragments = null;
98         fragmentExports = null;
99         fragmentImports = null;
100         fragmentRequires = null;
101         fragmentGenericRequires = null;
102     }
103
104     ResolverExport getExport(String JavaDoc name) {
105         ResolverExport[] allExports = getExports(name);
106         return allExports.length == 0 ? null : allExports[0];
107     }
108
109     ResolverExport[] getExports(String JavaDoc name) {
110         ArrayList results = new ArrayList(1); // rare to have more than one
111
// it is faster to ask the VersionHashMap for this package name and then compare the exporter to this
112
Object JavaDoc[] resolverExports = resolver.getResolverExports().get(name);
113         for (int i = 0; i < resolverExports.length; i++)
114             if (((ResolverExport)resolverExports[i]).getExporter() == this)
115                 results.add(resolverExports[i]);
116         return (ResolverExport[]) results.toArray(new ResolverExport[results.size()]);
117     }
118
119     void clearWires() {
120         ResolverImport[] allImports = getImportPackages();
121         for (int i = 0; i < allImports.length; i++)
122             allImports[i].clearPossibleSuppliers();
123
124         if (host != null)
125             host.clearPossibleSuppliers();
126
127         BundleConstraint[] allRequires = getRequires();
128         for (int i = 0; i < allRequires.length; i++)
129             allRequires[i].clearPossibleSuppliers();
130
131         GenericConstraint[] allGenericRequires = getGenericRequires();
132         for (int i = 0; i < allGenericRequires.length; i++)
133             allGenericRequires[i].setMatchingCapability(null);
134     }
135
136     boolean isResolved() {
137         return getState() == ResolverBundle.RESOLVED;
138     }
139
140     boolean isFragment() {
141         return host != null;
142     }
143
144     int getState() {
145         return state;
146     }
147
148     void setState(int state) {
149         this.state = state;
150     }
151
152     ResolverImport[] getImportPackages() {
153         if (isFragment())
154             return new ResolverImport[0];
155         if (fragments == null || fragments.size() == 0)
156             return imports;
157         ArrayList resultList = new ArrayList(imports.length);
158         for (int i = 0; i < imports.length; i++)
159             resultList.add(imports[i]);
160         for (Iterator iter = fragments.iterator(); iter.hasNext();) {
161             ResolverBundle fragment = (ResolverBundle) iter.next();
162             ArrayList fragImports = (ArrayList) fragmentImports.get(fragment.bundleID);
163             if (fragImports != null)
164                 resultList.addAll(fragImports);
165         }
166         return (ResolverImport[]) resultList.toArray(new ResolverImport[resultList.size()]);
167     }
168
169     ResolverExport[] getExportPackages() {
170         if (isFragment())
171             return new ResolverExport[0];
172         if (fragments == null || fragments.size() == 0)
173             return exports;
174         ArrayList resultList = new ArrayList(exports.length);
175         for (int i = 0; i < exports.length; i++)
176             resultList.add(exports[i]);
177         for (Iterator iter = fragments.iterator(); iter.hasNext();) {
178             ResolverBundle fragment = (ResolverBundle) iter.next();
179             ArrayList fragExports = (ArrayList) fragmentExports.get(fragment.bundleID);
180             if (fragExports != null)
181                 resultList.addAll(fragExports);
182         }
183         return (ResolverExport[]) resultList.toArray(new ResolverExport[resultList.size()]);
184     }
185
186     ResolverExport[] getSelectedExports() {
187         ResolverExport[] allExports = getExportPackages();
188         int removedExports = 0;
189         for (int i = 0; i < allExports.length; i++)
190             if (allExports[i].isDropped())
191                 removedExports++;
192         if (removedExports == 0)
193             return allExports;
194         ResolverExport[] selectedExports = new ResolverExport[allExports.length - removedExports];
195         int index = 0;
196         for (int i = 0; i < allExports.length; i++) {
197             if (allExports[i].isDropped())
198                 continue;
199             selectedExports[index] = allExports[i];
200             index++;
201         }
202         return selectedExports;
203     }
204
205     BundleConstraint getHost() {
206         return host;
207     }
208
209     GenericCapability[] getGenericCapabilities() {
210         return capabilities;
211     }
212
213     BundleConstraint[] getRequires() {
214         if (isFragment())
215             return new BundleConstraint[0];
216         if (fragments == null || fragments.size() == 0)
217             return requires;
218         ArrayList resultList = new ArrayList(requires.length);
219         for (int i = 0; i < requires.length; i++)
220             resultList.add(requires[i]);
221         for (Iterator iter = fragments.iterator(); iter.hasNext();) {
222             ResolverBundle fragment = (ResolverBundle) iter.next();
223             ArrayList fragRequires = (ArrayList) fragmentRequires.get(fragment.bundleID);
224             if (fragRequires != null)
225                 resultList.addAll(fragRequires);
226         }
227         return (BundleConstraint[]) resultList.toArray(new BundleConstraint[resultList.size()]);
228     }
229
230     GenericConstraint[] getGenericRequires() {
231         if (isFragment() || fragments == null || fragments.size() == 0)
232             return genericReqiures;
233         ArrayList resultList = new ArrayList(genericReqiures.length);
234         for (int i = 0; i < genericReqiures.length; i++)
235             resultList.add(genericReqiures[i]);
236         for (Iterator iter = fragments.iterator(); iter.hasNext();) {
237             ResolverBundle fragment = (ResolverBundle) iter.next();
238             ArrayList fragGenericRegs = (ArrayList) fragmentGenericRequires.get(fragment.bundleID);
239             if (fragGenericRegs != null)
240                 resultList.addAll(fragGenericRegs);
241         }
242         return (GenericConstraint[]) resultList.toArray(new GenericConstraint[resultList.size()]);
243     }
244
245     BundleConstraint getRequire(String JavaDoc name) {
246         BundleConstraint[] allRequires = getRequires();
247         for (int i = 0; i < allRequires.length; i++)
248             if (allRequires[i].getVersionConstraint().getName().equals(name))
249                 return allRequires[i];
250         return null;
251     }
252
253     public BundleDescription getBundle() {
254         return (BundleDescription) getBaseDescription();
255     }
256
257     ResolverImport getImport(String JavaDoc name) {
258         ResolverImport[] allImports = getImportPackages();
259         for (int i = 0; i < allImports.length; i++) {
260             if (allImports[i].getName().equals(name)) {
261                 return allImports[i];
262             }
263         }
264         return null;
265     }
266
267     public String JavaDoc toString() {
268         return "[" + getBundle() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
269
}
270
271     private void initFragments() {
272         if (fragments == null)
273             fragments = new ArrayList(1);
274         if (fragmentExports == null)
275             fragmentExports = new HashMap(1);
276         if (fragmentImports == null)
277             fragmentImports = new HashMap(1);
278         if (fragmentRequires == null)
279             fragmentRequires = new HashMap(1);
280         if (fragmentGenericRequires == null)
281             fragmentGenericRequires = new HashMap(1);
282     }
283
284     private boolean isImported(String JavaDoc packageName) {
285         ResolverImport[] allImports = getImportPackages();
286         for (int i = 0; i < allImports.length; i++)
287             if (packageName.equals(allImports[i].getName()))
288                 return true;
289
290         return false;
291     }
292
293     private boolean isExported(String JavaDoc packageName) {
294         ResolverExport export = getExport(packageName);
295         if (export == null)
296             return false;
297         // let exports from a bundle manifest be exported in addition to the ones from the vm profile
298
return 0 > ((Integer JavaDoc) export.getExportPackageDescription().getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue();
299     }
300
301     private boolean isRequired(String JavaDoc bundleName) {
302         return getRequire(bundleName) != null;
303     }
304
305     ResolverExport[] attachFragment(ResolverBundle fragment, boolean dynamicAttach) {
306         if (isFragment())
307             return new ResolverExport[0]; // cannot attach to fragments;
308
if (!getBundle().attachFragments() || (isResolved() && !getBundle().dynamicFragments()))
309             return new ResolverExport[0]; // host is restricting attachment
310
if (fragment.getHost().getNumPossibleSuppliers() > 0 && !((HostSpecification) fragment.getHost().getVersionConstraint()).isMultiHost())
311             return new ResolverExport[0]; // fragment is restricting attachment
312

313         ImportPackageSpecification[] newImports = fragment.getBundle().getImportPackages();
314         BundleSpecification[] newRequires = fragment.getBundle().getRequiredBundles();
315         ExportPackageDescription[] newExports = fragment.getBundle().getExportPackages();
316         GenericSpecification[] newGenericRequires = fragment.getBundle().getGenericRequires();
317
318         // if this is not during initialization then check if constraints conflict
319
if (dynamicAttach && constraintsConflict(fragment.getBundle(), newImports, newRequires, newGenericRequires))
320             return new ResolverExport[0]; // do not allow fragments with conflicting constraints
321
if (isResolved() && newExports.length > 0)
322             fragment.setNewFragmentExports(true);
323
324         initFragments();
325         if (fragments.contains(fragment))
326             return new ResolverExport[0];
327         fragments.add(fragment);
328         fragment.getHost().addPossibleSupplier(this);
329
330         if (newImports.length > 0) {
331             ArrayList hostImports = new ArrayList(newImports.length);
332             for (int i = 0; i < newImports.length; i++)
333                 if (!isImported(newImports[i].getName()))
334                     hostImports.add(new ResolverImport(this, newImports[i]));
335             fragmentImports.put(fragment.bundleID, hostImports);
336         }
337
338         if (newRequires.length > 0) {
339             ArrayList hostRequires = new ArrayList(newRequires.length);
340             for (int i = 0; i < newRequires.length; i++)
341                 if (!isRequired(newRequires[i].getName()))
342                     hostRequires.add(new BundleConstraint(this, newRequires[i]));
343             fragmentRequires.put(fragment.bundleID, hostRequires);
344         }
345
346         if (newGenericRequires.length > 0) {
347             ArrayList hostGenericRequires = new ArrayList(newGenericRequires.length);
348             for (int i = 0; i < newGenericRequires.length; i++)
349                 hostGenericRequires.add(new GenericConstraint(this, newGenericRequires[i]));
350             fragmentGenericRequires.put(fragment.bundleID, hostGenericRequires);
351         }
352
353         ArrayList hostExports = new ArrayList(newExports.length);
354         if (newExports.length > 0 && dynamicAttach) {
355             StateObjectFactory factory = resolver.getState().getFactory();
356             for (int i = 0; i < newExports.length; i++) {
357                 if (!isExported(newExports[i].getName())) {
358                     ExportPackageDescription hostExport = factory.createExportPackageDescription(newExports[i].getName(), newExports[i].getVersion(), newExports[i].getDirectives(), newExports[i].getAttributes(), newExports[i].isRoot(), getBundle());
359                     hostExports.add(new ResolverExport(this, hostExport));
360                 }
361             }
362             fragmentExports.put(fragment.bundleID, hostExports);
363         }
364         return (ResolverExport[]) hostExports.toArray(new ResolverExport[hostExports.size()]);
365     }
366
367     boolean constraintsConflict(BundleDescription fragment, ImportPackageSpecification[] newImports, BundleSpecification[] newRequires, GenericSpecification[] newGenericRequires) {
368         // this method iterates over all additional constraints from a fragment
369
// if the host is resolved then the fragment is not allowed to add new constraints;
370
// if the host is resolved and it already has a constraint of the same name then ensure the supplier satisfies the fragment's constraint
371
boolean result = false;
372         for (int i = 0; i < newImports.length; i++) {
373             ResolverImport hostImport = getImport(newImports[i].getName());
374             ResolverExport resolvedExport = (ResolverExport) (hostImport == null ? null : hostImport.getSelectedSupplier());
375             if ((resolvedExport == null && isResolved()) || (resolvedExport != null && !newImports[i].isSatisfiedBy(resolvedExport.getExportPackageDescription()))) {
376                 result = true;
377                 resolver.getState().addResolverError(fragment, ResolverError.FRAGMENT_CONFLICT, newImports[i].toString(), newImports[i]);
378             }
379         }
380         for (int i = 0; i < newRequires.length; i++) {
381             BundleConstraint hostRequire = getRequire(newRequires[i].getName());
382             ResolverBundle resolvedRequire = (ResolverBundle) (hostRequire == null ? null : hostRequire.getSelectedSupplier());
383             if ((resolvedRequire == null && isResolved()) || (resolvedRequire != null && !newRequires[i].isSatisfiedBy(resolvedRequire.getBundle()))) {
384                 result = true;
385                 resolver.getState().addResolverError(fragment, ResolverError.FRAGMENT_CONFLICT, newRequires[i].toString(), newRequires[i]);
386             }
387         }
388         // generic constraints cannot conflict;
389
// only check that a fragment does not add generics constraints to an already resolved host
390
if (isResolved() && newGenericRequires != null && newGenericRequires.length > 0)
391             result = true;
392         return result;
393     }
394
395     private void setNewFragmentExports(boolean newFragmentExports) {
396         this.newFragmentExports = newFragmentExports;
397     }
398
399     boolean isNewFragmentExports() {
400         return newFragmentExports;
401     }
402
403     ResolverExport[] detachFragment(ResolverBundle fragment, ResolverConstraint reason) {
404         if (isFragment())
405             return new ResolverExport[0];
406         initFragments();
407
408         if (!fragments.remove(fragment))
409             return new ResolverExport[0];
410
411         fragment.setNewFragmentExports(false);
412         fragment.getHost().removePossibleSupplier(this);
413         ArrayList fragImports = (ArrayList) fragmentImports.remove(fragment.bundleID);
414         ArrayList fragRequires = (ArrayList) fragmentRequires.remove(fragment.bundleID);
415         ArrayList removedExports = (ArrayList) fragmentExports.remove(fragment.bundleID);
416         fragmentGenericRequires.remove(fragment.bundleID);
417         if (reason != null) {
418             ResolverBundle[] remainingFrags = (ResolverBundle[]) fragments.toArray(new ResolverBundle[fragments.size()]);
419             for (int i = 0; i < remainingFrags.length; i++) {
420                 resolver.getResolverExports().remove(detachFragment(remainingFrags[i], null));
421                 VersionConstraint[] constraints;
422                 if (reason instanceof ResolverImport)
423                     constraints = remainingFrags[i].getBundle().getImportPackages();
424                 else
425                     constraints = remainingFrags[i].getBundle().getRequiredBundles();
426                 for (int j = 0; j < constraints.length; j++)
427                     if (reason.getName().equals(constraints[j].getName()))
428                         continue; // this fragment should remained unattached.
429
resolver.getResolverExports().put(attachFragment(remainingFrags[i], true));
430                 ArrayList newImports = (ArrayList) fragmentImports.get(remainingFrags[i].bundleID);
431                 if (newImports != null && fragImports != null)
432                     for (Iterator iNewImports = newImports.iterator(); iNewImports.hasNext();) {
433                         ResolverImport newImport = (ResolverImport) iNewImports.next();
434                         for (Iterator iOldImports = fragImports.iterator(); iOldImports.hasNext();) {
435                             ResolverImport oldImport = (ResolverImport) iOldImports.next();
436                             if (newImport.getName().equals(oldImport.getName()))
437                                 newImport.setPossibleSuppliers(oldImport.getPossibleSuppliers());
438                         }
439                     }
440                 ArrayList newRequires = (ArrayList) fragmentRequires.get(remainingFrags[i].bundleID);
441                 if (newRequires != null && fragRequires != null)
442                     for (Iterator iNewRequires = newRequires.iterator(); iNewRequires.hasNext();) {
443                         BundleConstraint newRequire = (BundleConstraint) iNewRequires.next();
444                         for (Iterator iOldRequires = fragRequires.iterator(); iOldRequires.hasNext();) {
445                             BundleConstraint oldRequire = (BundleConstraint) iOldRequires.next();
446                             if (newRequire.getName().equals(oldRequire.getName()))
447                                 newRequire.setPossibleSuppliers(oldRequire.getPossibleSuppliers());
448                         }
449                     }
450             }
451         }
452         return removedExports == null ? new ResolverExport[0] : (ResolverExport[]) removedExports.toArray(new ResolverExport[removedExports.size()]);
453     }
454
455     void detachAllFragments() {
456         if (fragments == null)
457             return;
458         ResolverBundle[] allFragments = (ResolverBundle[]) fragments.toArray(new ResolverBundle[fragments.size()]);
459         for (int i = 0; i < allFragments.length; i++)
460             detachFragment(allFragments[i], null);
461     }
462
463     boolean isResolvable() {
464         return resolvable;
465     }
466
467     void setResolvable(boolean resolvable) {
468         this.resolvable = resolvable;
469     }
470
471     void addExport(ResolverExport re) {
472         ResolverExport[] newExports = new ResolverExport[exports.length + 1];
473         for (int i = 0; i < exports.length; i++)
474             newExports[i] = exports[i];
475         newExports[exports.length] = re;
476         exports = newExports;
477     }
478
479     ResolverImpl getResolver() {
480         return resolver;
481     }
482
483     void clearRefs() {
484         if (refs != null)
485             refs.clear();
486     }
487
488     void addRef(ResolverBundle ref) {
489         if (refs != null && !refs.contains(ref))
490             refs.add(ref);
491     }
492
493     int getRefs() {
494         return refs == null ? 0 : refs.size();
495     }
496
497     ResolverBundle[] getFragments() {
498         return fragments == null ? new ResolverBundle[0] : (ResolverBundle[]) fragments.toArray(new ResolverBundle[fragments.size()]);
499     }
500
501     /*
502      * This is used to sort bundles by BSN. This is needed to fix bug 174930
503      * If both BSNs are null then 0 is returned
504      * If this BSN is null the 1 is returned
505      * If the other BSN is null then -1 is returned
506      * otherwise String.compareTo is used
507      */

508     public int compareTo(Object JavaDoc o) {
509         String JavaDoc bsn = getName();
510         String JavaDoc otherBsn = ((ResolverBundle) o).getName();
511         if (bsn == null)
512             return otherBsn == null ? 0 : 1;
513         return otherBsn == null ? -1 : bsn.compareTo(otherBsn);
514     }
515 }
516
Popular Tags