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.io.*;
00038 import java.net.*;
00039 import java.security.ProtectionDomain;
00040 import java.util.ArrayList;
00041 import java.util.Enumeration;
00042 import java.util.HashSet;
00043 import java.util.Hashtable;
00044 import java.util.Iterator;
00045 import java.util.Map;
00046 import java.util.Vector;
00047
00048 import org.osgi.framework.*;
00049
00057 final public class BundleClassLoader extends ClassLoader {
00058
00062 final private boolean debug = Debug.classLoader;
00063
00067 final static private ClassLoader parent = Framework.class.getClassLoader();
00068
00072 private static boolean isJava2;
00073
00077 final PermissionOps secure;
00078
00082 final ProtectionDomain protectionDomain;
00083
00087 private BundleArchive archive;
00088
00092 private ArrayList fragments;
00093
00097 private BundlePackages bpkgs;
00098
00099 private static ArrayList bootDelegationPatterns = new ArrayList(1);
00100 private static boolean bootDelegationUsed ;
00101
00102
00103 static {
00104 try {
00105 ClassLoader.class.getDeclaredMethod("findLibrary", new Class [] { String.class });
00106 isJava2 = true;
00107 } catch (NoSuchMethodException ignore) {
00108 isJava2 = false;
00109 }
00110
00111 buildBootDelegationPatterns();
00112 }
00113
00114
00115 static void buildBootDelegationPatterns() {
00116 String bootDelegationString = System.getProperty(Constants.FRAMEWORK_BOOTDELEGATION);
00117 bootDelegationUsed = (bootDelegationString != null);
00118
00119 try {
00120 Iterator i = Util.parseEntries(Constants.FRAMEWORK_BOOTDELEGATION,
00121 bootDelegationString,
00122 true, true, false);
00123
00124 while (i.hasNext()) {
00125 Map e = (Map)i.next();
00126 String key = (String)e.get("key");
00127 if (key.equals("*")) {
00128 bootDelegationPatterns = null;
00129
00130 break;
00131 }
00132 else if (key.endsWith(".*")) {
00133 bootDelegationPatterns.add(key.substring(0, key.length() - 1));
00134 }
00135 else if (key.endsWith(".")) {
00136 Main.framework.listeners.frameworkError(Main.framework.systemBundle, new IllegalArgumentException(
00137 Constants.FRAMEWORK_BOOTDELEGATION + " entry ends with '.': " + key));
00138 }
00139 else if (key.indexOf("*") != - 1) {
00140 Main.framework.listeners.frameworkError(Main.framework.systemBundle, new IllegalArgumentException(
00141 Constants.FRAMEWORK_BOOTDELEGATION + " entry contains a '*': " + key));
00142 }
00143 else {
00144 bootDelegationPatterns.add(key);
00145 }
00146 }
00147 }
00148 catch (IllegalArgumentException e) {
00149 Main.framework.listeners.frameworkError(Main.framework.systemBundle, e);
00150 }
00151 }
00152
00153 static boolean isBootDelegated(String className){
00154 if(!bootDelegationUsed){
00155 return false;
00156 }
00157 int pos = className.lastIndexOf('.');
00158 if (pos != -1) {
00159 String classPackage = className.substring(0, pos);
00160 if (bootDelegationPatterns == null) {
00161 return true;
00162 }
00163 else {
00164 for (Iterator i = bootDelegationPatterns.iterator(); i.hasNext(); ) {
00165 String ps = (String)i.next();
00166 if ((ps.endsWith(".") &&
00167 classPackage.regionMatches(0, ps, 0, ps.length() - 1)) ||
00168 classPackage.equals(ps)) {
00169 return true;
00170 }
00171 }
00172 }
00173 }
00174 return false;
00175 }
00176
00177
00181 BundleClassLoader(BundlePackages bpkgs, BundleArchive ba, ArrayList frags,
00182 ProtectionDomain pd, PermissionOps secure) {
00183 super(parent);
00184 this.secure = secure;
00185 protectionDomain = pd;
00186 this.bpkgs = bpkgs;
00187 archive = ba;
00188 fragments = frags;
00189 if (debug) {
00190 Debug.println(this + " Created new classloader");
00191 }
00192 }
00193
00194
00195
00196
00197
00205 protected Class findClass(String name) throws ClassNotFoundException {
00206 if (name.startsWith("java.")) {
00207 return parent.loadClass(name);
00208 }
00209 if (isBootDelegated(name)) {
00210 try {
00211 return parent.loadClass(name);
00212 } catch (ClassNotFoundException e) { }
00213 }
00214 if (secure.okClassAdminPerm(bpkgs.bundle)) {
00215 String path;
00216 String pkg;
00217 int pos = name.lastIndexOf('.');
00218 if (pos != -1) {
00219 path = name.replace('.', '/');
00220 pkg = name.substring(0, pos);
00221 } else {
00222 path = name;
00223 pkg = null;
00224 }
00225 Class res = (Class)secure.callSearchFor(this, name, pkg, path + ".class",
00226 classSearch, true, this, null);
00227 if (res != null) {
00228 return res;
00229 }
00230 }
00231 throw new ClassNotFoundException(name);
00232 }
00233
00234
00240 protected String findLibrary(String name) {
00241 String res = archive.getNativeLibrary(name);
00242 if (res == null && fragments != null) {
00243 for (Iterator i = fragments.iterator(); i.hasNext(); ) {
00244 res = ((BundleArchive)i.next()).getNativeLibrary(name);
00245 if (res != null) {
00246 break;
00247 }
00248 }
00249 }
00250 if (debug) {
00251 Debug.println(this + " Find library: " + name + (res != null ? " OK" : " FAIL"));
00252 }
00253 return res;
00254 }
00255
00256
00262 protected Enumeration findResources(String name) {
00263
00264 return getBundleResources(name, false);
00265 }
00266
00267
00273 protected URL findResource(String name) {
00274 Enumeration res = getBundleResources(name, true);
00275 if (res != null) {
00276 return (URL)res.nextElement();
00277 } else {
00278 return null;
00279 }
00280 }
00281
00282
00294 protected Class loadClass(String name, boolean resolve)
00295 throws ClassNotFoundException
00296 {
00297 Class c = findLoadedClass(name);
00298 if (c == null) {
00299 c = findClass(name);
00300 }
00301 if (resolve) {
00302 resolveClass(c);
00303 }
00304 return c;
00305 }
00306
00307
00320 public URL getResource(String name) {
00321 if (debug) {
00322 Debug.println(this + " getResource: " + name);
00323 }
00324 URL res = super.getResource(name);
00325 if (res == null && !isJava2) {
00326 return findResource(name);
00327 }
00328 return res;
00329 }
00330
00331
00342 public InputStream getResourceAsStream(String name) {
00343 try {
00344 URL url = getResource(name);
00345 if (url != null) {
00346 return url.openStream();
00347 }
00348 } catch (IOException ignore) { }
00349 return null;
00350 }
00351
00352
00358 public String toString() {
00359 return "BundleClassLoader(id=" + bpkgs.bundle.id + ",gen=" + bpkgs.generation + ")";
00360 }
00361
00362
00363
00364
00365
00369 BundleImpl getBundle() {
00370 return bpkgs.bundle;
00371 }
00372
00373
00377 BundleArchive getBundleArchive(long frag) {
00378 if (frag >= 0) {
00379 if (fragments != null) {
00380 for (Iterator i = fragments.iterator(); i.hasNext(); ) {
00381
00382 BundleArchive ba = (BundleArchive)i.next();
00383 if (ba.getBundleId() == frag) {
00384 return ba;
00385 }
00386 }
00387 }
00388 return null;
00389 } else {
00390 return archive;
00391 }
00392 }
00393
00394
00400 void close() {
00401 archive = null;
00402 bpkgs.invalidateClassLoader();
00403 if (debug) {
00404 Debug.println(this + " Cleared archives");
00405 }
00406 }
00407
00408
00414 void purge() {
00415 bpkgs.unregisterPackages(true);
00416 if (protectionDomain != null) {
00417 bpkgs.bundle.framework.perm.purge(bpkgs.bundle, protectionDomain);
00418 }
00419 if (archive != null) {
00420 archive.purge();
00421 }
00422 if (fragments != null) {
00423 for (Iterator i = fragments.iterator(); i.hasNext(); ) {
00424
00425 BundleArchive ba = (BundleArchive)i.next();
00426 BundleImpl b = (BundleImpl)bpkgs.bundle.framework.bundles.getBundle(ba.getBundleLocation());
00427 if (b == null || b.archive != ba) {
00428 ba.purge();
00429 }
00430 }
00431 }
00432 close();
00433 }
00434
00435
00440 Enumeration getBundleResources(String name, boolean onlyFirst) {
00441 if (secure.okResourceAdminPerm(bpkgs.bundle)) {
00442 if (debug) {
00443 Debug.println(this + " Find bundle resource" + (onlyFirst ? "" : "s") + ": " + name);
00444 }
00445 String pkg = null;
00446 int pos = name.lastIndexOf('/');
00447 if (pos > 0) {
00448 int start = name.startsWith("/") ? 1 : 0;
00449 pkg = name.substring(start, pos).replace('/', '.');
00450 } else {
00451 pkg = null;
00452 }
00453 return (Enumeration)secure.callSearchFor(this, null, pkg, name, resourceSearch,
00454 onlyFirst, this, null);
00455 } else {
00456 return null;
00457 }
00458 }
00459
00460
00465 Hashtable getLocalizationEntries(String name) {
00466 Hashtable localization_entries = null;
00467 if (fragments != null) {
00468 for (int i = fragments.size() - 1; i >= 0; i--) {
00469 BundleArchive ba = (BundleArchive)fragments.get(i);
00470 Hashtable tmp = ba.getLocalizationEntries(name);
00471 if (tmp != null) {
00472 if (localization_entries != null) {
00473 localization_entries.putAll(tmp);
00474 } else {
00475 localization_entries = tmp;
00476 }
00477 }
00478 }
00479 }
00480 Hashtable tmp = archive.getLocalizationEntries(name);
00481 if (tmp != null) {
00482 if (localization_entries != null) {
00483 localization_entries.putAll(tmp);
00484 } else {
00485 localization_entries = tmp;
00486 }
00487 }
00488 return localization_entries;
00489 }
00490
00491
00496 BundlePackages getBpkgs() {
00497 return bpkgs;
00498 }
00499
00500
00501
00502
00503
00558 Object searchFor(String name, String pkg, String path, SearchAction action,
00559 boolean onlyFirst, BundleClassLoader requestor, HashSet visited) {
00560 BundlePackages pbp;
00561 ExportPkg ep;
00562
00563
00564 if (action == classSearch && requestor != this) {
00565 Class c = findLoadedClass(name);
00566 if (c != null) {
00567 return c;
00568 }
00569 }
00570
00571 if (debug) {
00572 Debug.println(this + " Search for: " + path);
00573 }
00574
00575 if (pkg != null) {
00576 pbp = bpkgs.getProviderBundlePackages(pkg);
00577 if (pbp != null) {
00578
00579 if (isSystemBundle(pbp.bundle)) {
00580 try {
00581 return pbp.bundle.framework.systemBundle.getClassLoader().loadClass(name);
00582 } catch (ClassNotFoundException e) {
00583
00584 }
00585
00586 } else {
00587 BundleClassLoader cl = (BundleClassLoader)pbp.getClassLoader();
00588 if (cl != this) {
00589 if (cl != null) {
00590 if (debug) {
00591 Debug.println(this + " Import search: " + path +
00592 " from #" + pbp.bundle.id);
00593 }
00594 return secure.callSearchFor(cl, name, pkg, path, action,
00595 onlyFirst, requestor, visited);
00596 }
00597 if (debug) {
00598 Debug.println(this + " No import found: " + path);
00599 }
00600 return null;
00601 }
00602 }
00603 } else {
00604
00605 ArrayList pl = bpkgs.getRequiredBundlePackages(pkg);
00606 if (pl != null) {
00607 if (visited == null) {
00608 visited = new HashSet();
00609 }
00610 visited.add(this);
00611 for (Iterator pi = pl.iterator(); pi.hasNext(); ) {
00612 pbp = (BundlePackages)pi.next();
00613 if (pbp != null) {
00614 BundleClassLoader cl = (BundleClassLoader)pbp.getClassLoader();
00615 if (cl != null && !visited.contains(cl)) {
00616 if (debug) {
00617 Debug.println(this + " Required bundle search: " +
00618 path + " from #" + pbp.bundle.id);
00619 }
00620 Object res = secure.callSearchFor(cl, name, pkg, path, action,
00621 onlyFirst, requestor, visited);
00622 if (res != null) {
00623 return res;
00624 }
00625 }
00626 }
00627 }
00628 }
00629 }
00630 ep = bpkgs.getExport(pkg);
00631 } else {
00632 ep = null;
00633 }
00634
00635 if (this != requestor && ep != null && !ep.checkFilter(name)) {
00636 return null;
00637 }
00638 Vector av = archive.componentExists(path, onlyFirst);
00639 if (av != null) {
00640 try {
00641 return action.get(av, path, name, pkg, this, archive);
00642 } catch (IOException ioe) {
00643 bpkgs.bundle.framework.listeners.frameworkError(bpkgs.bundle, ioe);
00644 return null;
00645 }
00646 }
00647
00648 if (fragments != null) {
00649 for (Iterator i = fragments.iterator(); i.hasNext(); ) {
00650 BundleArchive ba = (BundleArchive)i.next();
00651 if (debug) {
00652 Debug.println(this + " Fragment bundle search: " +
00653 path + " from #" + ba.getBundleId());
00654 }
00655 Vector vec = ba.componentExists(path, onlyFirst);
00656 if (vec != null) {
00657 try {
00658 return action.get(vec, path, name, pkg, this, ba);
00659 } catch (IOException ioe) {
00660 bpkgs.bundle.framework.listeners.frameworkError(bpkgs.bundle, ioe);
00661 return null;
00662 }
00663 }
00664 }
00665 }
00666
00667 if (ep != null) {
00668 return null;
00669 }
00670
00671 if (pkg != null) {
00672 pbp = bpkgs.getDynamicProviderBundlePackages(pkg);
00673 if (pbp != null) {
00674
00675 if (isSystemBundle(pbp.bundle)) {
00676 try {
00677 return pbp.bundle.framework.systemBundle.getClassLoader().loadClass(name);
00678 } catch (ClassNotFoundException e) {
00679
00680 }
00681 } else {
00682 BundleClassLoader cl = (BundleClassLoader)pbp.getClassLoader();
00683 if (cl != null) {
00684 if (debug) {
00685 Debug.println(this + " Dynamic import search: " +
00686 path + " from #" + pbp.bundle.id);
00687 }
00688 return secure.callSearchFor(cl, name, pkg, path, action,
00689 onlyFirst, requestor, visited);
00690 }
00691 }
00692 }
00693 if (debug) {
00694 Debug.println(this + " No dynamic import: " + path);
00695 }
00696 }
00697 return null;
00698 }
00699
00700
00701 private static boolean isSystemBundle(BundleImpl bundle) {
00702 return bundle == bundle.framework.systemBundle;
00703 }
00704
00705
00709 interface SearchAction {
00710 public Object get(Vector items, String path, String name, String pkg,
00711 BundleClassLoader cl, BundleArchive ba) throws IOException ;
00712 }
00713
00714
00718 static final SearchAction classSearch = new SearchAction() {
00719 public Object get(Vector items, String path, String name, String pkg,
00720 BundleClassLoader cl, BundleArchive ba) throws IOException {
00721 byte[] bytes = ba.getClassBytes((Integer)items.get(0), path);
00722 if (bytes != null) {
00723 if (Debug.classLoader) {
00724 Debug.println("classLoader(#" + cl.bpkgs.bundle.id + ") - load class: " + name);
00725 }
00726 synchronized (cl) {
00727 Class c = cl.findLoadedClass(name);
00728 if (c == null) {
00729 if (pkg != null) {
00730 if (cl.getPackage(pkg) == null) {
00731 cl.definePackage(pkg, null, null, null, null, null, null, null);
00732 }
00733 }
00734 if (cl.protectionDomain == null) {
00735
00736 c = cl.defineClass(name, bytes, 0, bytes.length);
00737 } else {
00738 c = cl.defineClass(name, bytes, 0, bytes.length, cl.protectionDomain);
00739 }
00740 }
00741 return c;
00742 }
00743 }
00744 return null;
00745 }
00746 };
00747
00748
00752 static final SearchAction resourceSearch = new SearchAction() {
00753 public Object get(Vector items, String path, String name, String _pkg,
00754 BundleClassLoader cl, BundleArchive ba) {
00755 Vector answer = new Vector(items.size());
00756 for(int i = 0; i < items.size(); i++) {
00757 int subId = ((Integer)items.elementAt(i)).intValue();
00758 URL url = cl.bpkgs.bundle.getURL(cl.bpkgs.generation,
00759 ba.getBundleId(),
00760 subId,
00761 path);
00762 if (url != null) {
00763 if (Debug.classLoader) {
00764 Debug.println("classLoader(#" + cl.bpkgs.bundle.id + ") - found: " +
00765 path + " -> " + url);
00766 }
00767 answer.addElement(url);
00768 } else {
00769 return null;
00770 }
00771 }
00772 return answer.elements();
00773 }
00774 };
00775
00776 }