BundleClassLoader.java

00001 /*
00002  * Copyright (c) 2003-2006, KNOPFLERFISH project
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  * - Redistributions in binary form must reproduce the above
00013  *   copyright notice, this list of conditions and the following
00014  *   disclaimer in the documentation and/or other materials
00015  *   provided with the distribution.
00016  *
00017  * - Neither the name of the KNOPFLERFISH project nor the names of its
00018  *   contributors may be used to endorse or promote products derived
00019  *   from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00030  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032  * OF THE POSSIBILITY OF SUCH DAMAGE.
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 /* BundleArchive */ fragments;
00093 
00097   private BundlePackages bpkgs;
00098   
00099   private static ArrayList /* String */ bootDelegationPatterns = new ArrayList(1);
00100   private static boolean bootDelegationUsed /*= false*/;
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           //in case funny person puts a * amongst other things
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); //otherwise getResource will bypass OUR 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   // ClassLoader classes
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     // Step 1 and 2 are done by getResources?
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   // BundleClassLoader specific
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           // NYI improve this solution
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         // NYI improve this solution
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   // Private
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     // TBD! Should this be an action method
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     /* 3 */
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             // continue
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         /* 4 */
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     /* 5 */
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     /* 6 */
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     /* 7 */
00667     if (ep != null) {
00668       return null;
00669     }
00670     /* 8 */
00671     if (pkg != null) {
00672       pbp = bpkgs.getDynamicProviderBundlePackages(pkg);
00673       if (pbp != null) {
00674         /* 9 */
00675         if (isSystemBundle(pbp.bundle)) {
00676           try {
00677             return pbp.bundle.framework.systemBundle.getClassLoader().loadClass(name);
00678           } catch (ClassNotFoundException e) {
00679             // continue
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                 // Kaffe can't handle null protectiondomain
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 } //class

Generated on Mon Jan 11 21:19:13 2010 for OpenMobileIS by  doxygen 1.5.4