00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 package org.knopflerfish.framework;
00036
00037 import java.util.List;
00038 import java.util.ArrayList;
00039 import java.util.Map;
00040 import java.util.HashMap;
00041 import java.util.Iterator;
00042
00043 import org.osgi.framework.*;
00044
00045
00052 class BundlePackages {
00053
00054 final BundleImpl bundle;
00055
00056 final int generation;
00057
00058 private ClassLoader classLoader = null;
00059
00060
00061 private ArrayList exports = new ArrayList(1);
00062
00063
00064 private ArrayList imports = new ArrayList(1);
00065
00066 private ArrayList dImportPatterns = new ArrayList(1);
00067
00068 private HashMap fragments = null;
00069
00070
00071 ArrayList require;
00072
00073
00074 ArrayList requiredBy = null;
00075
00076
00077 private ArrayList okImports = null;
00078
00079
00080 private boolean registered = false;
00081
00082
00083 private String failReason = null;
00084
00085 final static String EMPTY_STRING = "";
00086
00090 BundlePackages(BundleImpl b,
00091 int gen,
00092 String exportStr,
00093 String importStr,
00094 String dimportStr,
00095 String requireStr) {
00096 this.bundle = b;
00097 this.generation = gen;
00098
00099 Iterator i = Util.parseEntries(Constants.IMPORT_PACKAGE, importStr, false, true, false);
00100 while (i.hasNext()) {
00101 Map e = (Map)i.next();
00102 Iterator pi = ((List)e.remove("keys")).iterator();
00103 ImportPkg ip = new ImportPkg((String)pi.next(), e, this);
00104 for (;;) {
00105 int ii = Util.binarySearch(imports, ipComp, ip);
00106 if (ii < 0) {
00107 imports.add(-ii - 1, ip);
00108 } else {
00109 throw new IllegalArgumentException("Duplicate import definitions for - " + ip.name);
00110 }
00111 if (pi.hasNext()) {
00112 ip = new ImportPkg(ip, (String)pi.next());
00113 } else {
00114 break;
00115 }
00116 }
00117 }
00118
00119 i = Util.parseEntries(Constants.EXPORT_PACKAGE, exportStr, false, true, false);
00120 while (i.hasNext()) {
00121 Map e = (Map)i.next();
00122 Iterator pi = ((List)e.remove("keys")).iterator();
00123 ExportPkg ep = new ExportPkg((String)pi.next(), e, this);
00124 for (;;) {
00125 int ei = Math.abs(Util.binarySearch(exports, epComp, ep) + 1);
00126 exports.add(ei, ep);
00127 if (!b.v2Manifest) {
00128 ImportPkg ip = new ImportPkg(ep);
00129 int ii = Util.binarySearch(imports, ipComp, ip);
00130 if (ii < 0) {
00131 imports.add(-ii - 1, ip);
00132 }
00133 }
00134 if (pi.hasNext()) {
00135 ep = new ExportPkg(ep, (String)pi.next());
00136 } else {
00137 break;
00138 }
00139 }
00140 }
00141
00142 i = Util.parseEntries(Constants.DYNAMICIMPORT_PACKAGE, dimportStr, false, true, false);
00143 while (i.hasNext()) {
00144 Map e = (Map)i.next();
00145 if (e.containsKey(Constants.RESOLUTION_DIRECTIVE)) {
00146 throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE +
00147 " entry illegal contains a " +
00148 Constants.RESOLUTION_DIRECTIVE +
00149 " directive.");
00150 }
00151 ImportPkg tmpl = null;
00152 for (Iterator pi = ((List)e.remove("keys")).iterator(); pi.hasNext(); ) {
00153 String key = (String)pi.next();
00154 if (key.equals("*")) {
00155 key = EMPTY_STRING;
00156 } else if (key.endsWith(".*")) {
00157 key = key.substring(0, key.length() - 1);
00158 } else if (key.endsWith(".")) {
00159 throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE +
00160 " entry ends with '.': " + key);
00161 } else if (key.indexOf("*") != - 1) {
00162 throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE +
00163 " entry contains a '*': " + key);
00164 }
00165 if (tmpl != null) {
00166 dImportPatterns.add(new ImportPkg(tmpl, key));
00167 } else {
00168 tmpl = new ImportPkg(key, e, this);
00169 dImportPatterns.add(tmpl);
00170 }
00171 }
00172 }
00173 i = Util.parseEntries(Constants.REQUIRE_BUNDLE, requireStr, true, true, false);
00174 if (i.hasNext()) {
00175 require = new ArrayList();
00176 do {
00177 Map e = (Map)i.next();
00178 require.add(new RequireBundle(this,
00179 (String)e.get("key"),
00180 (String)e.get(Constants.VISIBILITY_DIRECTIVE),
00181 (String)e.get(Constants.RESOLUTION_DIRECTIVE),
00182 (String)e.get(Constants.BUNDLE_VERSION_ATTRIBUTE)));
00183
00184 } while (i.hasNext());
00185 } else {
00186 require = null;
00187 }
00188
00189 }
00190
00191
00196 void registerPackages() {
00197 bundle.framework.packages.registerPackages(exports.iterator(), imports.iterator());
00198 registered = true;
00199 }
00200
00201
00206 synchronized boolean unregisterPackages(boolean force) {
00207 if (registered) {
00208 List i = okImports != null ? okImports : imports;
00209 if (bundle.framework.packages.unregisterPackages(exports, i, force)) {
00210 okImports = null;
00211 registered = false;
00212 } else {
00213 return false;
00214 }
00215 }
00216 return true;
00217 }
00218
00219
00227 boolean resolvePackages() {
00228 ArrayList permImports = new ArrayList(imports.size());
00229 failReason = bundle.framework.perm.missingMandatoryPackagePermissions(this, permImports);
00230 if (failReason != null) {
00231 return false;
00232 }
00233 failReason = bundle.framework.packages.resolve(bundle, permImports.iterator());
00234 if (failReason == null) {
00235 for (Iterator i = permImports.iterator(); i.hasNext(); ) {
00236 ImportPkg ip = (ImportPkg)i.next();
00237 if (ip.provider == null) {
00238 i.remove();
00239 }
00240 }
00241 okImports = permImports;
00242 return true;
00243 } else {
00244 return false;
00245 }
00246 }
00247
00248
00254 String getResolveFailReason() {
00255 return failReason;
00256 }
00257
00258
00266 synchronized BundlePackages getProviderBundlePackages(String pkg) {
00267 if (okImports == null) {
00268 return null;
00269 }
00270 int ii = Util.binarySearch(okImports, ipFind, pkg);
00271 if (ii >= 0) {
00272 return ((ImportPkg)okImports.get(ii)).provider.bpkgs;
00273 }
00274 return null;
00275 }
00276
00277
00285 synchronized BundlePackages getDynamicProviderBundlePackages(String pkg) {
00286 if (okImports == null) {
00287 return null;
00288 }
00289 int ii = Util.binarySearch(okImports, ipFind, pkg);
00290 if (ii >= 0) {
00291 return ((ImportPkg)okImports.get(ii)).provider.bpkgs;
00292 }
00293 if (bundle.framework.perm.hasImportPackagePermission(bundle, pkg)) {
00294 for (Iterator i = dImportPatterns.iterator(); i.hasNext(); ) {
00295 ImportPkg ip = (ImportPkg)i.next();
00296 if (ip.name == EMPTY_STRING ||
00297 (ip.name.endsWith(".") && pkg.startsWith(ip.name)) ||
00298 pkg.equals(ip.name)) {
00299 ImportPkg nip = new ImportPkg(ip, pkg);
00300 ExportPkg ep = bundle.framework.packages.registerDynamicImport(nip);
00301 if (ep != null) {
00302 nip.provider = ep;
00303 okImports.add(-ii - 1, nip);
00304 return ep.bpkgs;
00305 }
00306 }
00307 }
00308 }
00309 return null;
00310 }
00311
00312
00321 ArrayList getRequiredBundlePackages(String pkg) {
00322 if (require != null) {
00323 ArrayList res = new ArrayList();
00324 for (Iterator i = require.iterator(); i.hasNext(); ) {
00325 RequireBundle rb = (RequireBundle)i.next();
00326 if (rb.bpkgs != null && rb.bpkgs.getExport(pkg) != null) {
00327 res.add(rb.bpkgs);
00328 }
00329 }
00330 if (!res.isEmpty()) {
00331 return res;
00332 }
00333 }
00334 return null;
00335 }
00336
00337
00344 List getRequiredBy() {
00345 if (requiredBy != null) {
00346 return (List)requiredBy.clone();
00347 }
00348 return new ArrayList(0);
00349 }
00350
00351
00357 void checkReExport(ExportPkg ep) {
00358 int i = Util.binarySearch(exports, epFind, ep.name);
00359 if (i < 0) {
00360 ExportPkg nep = new ExportPkg(ep, this);
00361 exports.add(-i - 1, nep);
00362
00363 ep.pkg.addExporter(nep);
00364 }
00365 }
00366
00367
00373 ExportPkg getExport(String pkg) {
00374 int i = Util.binarySearch(exports, epFind, pkg);
00375 if (i >= 0) {
00376 return (ExportPkg)exports.get(i);
00377 } else {
00378 return null;
00379 }
00380 }
00381
00382
00388 Iterator getExports() {
00389 return exports.iterator();
00390 }
00391
00396 void addExport(ExportPkg pkg) {
00397 int ei = Math.abs(Util.binarySearch(exports, epComp, pkg) + 1);
00398 exports.add(ei, pkg);
00399 }
00400
00401
00406 void removeExport(ExportPkg pkg) {
00407 int ei = Util.binarySearch(exports, epComp, pkg);
00408 exports.remove(ei);
00409 }
00410
00411
00416 ImportPkg getImport(String pkg) {
00417 int i = Util.binarySearch(imports, ipFind, pkg);
00418 if (i >= 0) {
00419 return (ImportPkg)imports.get(i);
00420 } else {
00421 return null;
00422 }
00423 }
00424
00425
00431 Iterator getImports() {
00432 return imports.iterator();
00433 }
00434
00435
00441 Iterator getActiveImports() {
00442 return okImports.iterator();
00443 }
00444
00445
00451 ClassLoader getClassLoader() {
00452 if (classLoader == null) {
00453 classLoader = bundle.getClassLoader(this);
00454 }
00455 return classLoader;
00456 }
00457
00458
00463 void invalidateClassLoader() {
00464 classLoader = null;
00465 }
00466
00467
00473 boolean isRegistered() {
00474 return registered;
00475 }
00476
00477
00483 String attachFragment(BundlePackages fbpkgs) {
00484 if (fragments == null) {
00485 fragments = new HashMap();
00486 } else if (fragments.containsKey(fbpkgs.bundle)) {
00487 throw new RuntimeException("Fragments packages already attached: " + fbpkgs);
00488 }
00489
00490
00491
00492 for (Iterator iiter = fbpkgs.getImports(); iiter.hasNext(); ) {
00493 ImportPkg fip = (ImportPkg)iiter.next();
00494 ImportPkg ip = getImport(fip.name);
00495
00496 if (ip == null && bundle.state != Bundle.INSTALLED) {
00497 return "Can not dynamicly attach, because host has no import for: " + fip;
00498 }
00499
00500 if (ip != null) {
00501 if (!fip.overlap(ip)) {
00502 return "Host bundle import package constraints need to be stricter" +
00503 "then the import package contraints in the attaching fragment.";
00504 }
00505 }
00506 }
00507
00508 ArrayList newRequired = new ArrayList();
00509 if (fbpkgs.require != null) {
00510 for (Iterator iter = fbpkgs.require.iterator(); iter.hasNext(); ) {
00511 RequireBundle fragReq = (RequireBundle)iter.next();
00512 boolean match = false;
00513
00514 if (require != null) {
00515
00516 for (Iterator iter2 = require.iterator(); iter2.hasNext(); ) {
00517 RequireBundle req = (RequireBundle)iter2.next();
00518 if (fragReq.name.equals(req.name)) {
00519 if (fragReq.overlap(req)) {
00520 match = true;
00521 } else {
00522 return "Fragment bundle required bundle does not completely overlap " +
00523 "required bundle in host bundle.";
00524 }
00525 }
00526 }
00527 }
00528 if (!match) {
00529 if (bundle.state != Bundle.INSTALLED) {
00530 return "Can not attach a fragment with new required bundles to a resolved host";
00531 }
00532 newRequired.add(fragReq);
00533 }
00534 }
00535 }
00536 Iterator riter = newRequired.iterator();
00537 if (riter.hasNext()) {
00538 int rpos;
00539 if (require == null) {
00540 require = new ArrayList();
00541 rpos = 0;
00542 } else {
00543 rpos = require.size();
00544 for (; rpos > 0; rpos--) {
00545 RequireBundle rb = (RequireBundle)require.get(rpos - 1);
00546 if (this == rb.bpkgs) {
00547 break;
00548 }
00549 if (rb.bpkgs.bundle.id < fbpkgs.bundle.id) {
00550 break;
00551 }
00552 }
00553 }
00554 do {
00555 require.add(rpos++, (RequireBundle)riter.next());
00556 } while (riter.hasNext());
00557 }
00558
00559 ArrayList newExports = new ArrayList();
00560 for (Iterator eiter = fbpkgs.getExports(); eiter.hasNext(); ) {
00561 ExportPkg fep = (ExportPkg) eiter.next();
00562 int ei = Util.binarySearch(exports, epComp, fep);
00563 if (ei < 0) {
00564 ExportPkg tmp = new ExportPkg(fep, this);
00565 exports.add(-ei - 1, tmp);
00566 newExports.add(tmp);
00567 }
00568 }
00569
00570 ArrayList newImports = new ArrayList();
00571 for (Iterator iiter = fbpkgs.getImports(); iiter.hasNext(); ) {
00572 ImportPkg fip = (ImportPkg)iiter.next();;
00573 int ii = Util.binarySearch(imports, ipComp, fip);
00574 if (ii < 0) {
00575 ImportPkg tmp = new ImportPkg(fip, this);
00576 imports.add(-ii - 1, tmp);
00577 newImports.add(tmp);
00578 }
00579 }
00580
00581 bundle.framework.packages.registerPackages(newExports.iterator(), newImports.iterator());
00582 fragments.put(fbpkgs.bundle, new ArrayList [] { newRequired, newExports, newImports });
00583 return null;
00584 }
00585
00586
00590 void detachFragment(BundleImpl fb) {
00591 if (registered) {
00592 throw new RuntimeException("NYI, detach when bpkgs are registered");
00593 }
00594 List [] added = (List [])fragments.remove(fb);
00595 for (Iterator riter = added[0].iterator(); riter.hasNext(); ) {
00596 require.remove(riter.next());
00597 }
00598 for (Iterator eiter = added[1].iterator(); eiter.hasNext(); ) {
00599 exports.remove(eiter.next());
00600 }
00601 for (Iterator iiter = added[2].iterator(); iiter.hasNext(); ) {
00602 imports.remove(iiter.next());
00603 }
00604 }
00605
00606
00612 public String toString() {
00613 return "BundlePackages(id=" + bundle.id + ",gen=" + generation + ")";
00614 }
00615
00616
00617
00618
00619
00620 static final Util.Comparator epComp = new Util.Comparator() {
00630 public int compare(Object oa, Object ob) throws ClassCastException {
00631 ExportPkg a = (ExportPkg)oa;
00632 ExportPkg b = (ExportPkg)ob;
00633 return a.name.compareTo(b.name);
00634 }
00635 };
00636
00637 static final Util.Comparator epFind = new Util.Comparator() {
00647 public int compare(Object oa, Object ob) throws ClassCastException {
00648 ExportPkg a = (ExportPkg)oa;
00649 String b = (String)ob;
00650 return a.name.compareTo(b);
00651 }
00652 };
00653
00654 static final Util.Comparator ipComp = new Util.Comparator() {
00664 public int compare(Object oa, Object ob) throws ClassCastException {
00665 ImportPkg a = (ImportPkg)oa;
00666 ImportPkg b = (ImportPkg)ob;
00667 return a.name.compareTo(b.name);
00668 }
00669 };
00670
00671 static final Util.Comparator ipFind = new Util.Comparator() {
00681 public int compare(Object oa, Object ob) throws ClassCastException {
00682 ImportPkg a = (ImportPkg)oa;
00683 String b = (String)ob;
00684 return a.name.compareTo(b);
00685 }
00686 };
00687
00688 }