Source for gnu.gcj.runtime.SharedLibHelper

   1: /* Copyright (C) 2001, 2003, 2004, 2005  Free Software Foundation
   2: 
   3:    This file is part of libgcj.
   4: 
   5: This software is copyrighted work licensed under the terms of the
   6: Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
   7: details.  */
   8: 
   9: package gnu.gcj.runtime;
  10: import java.lang.ref.WeakReference;
  11: import java.net.URL;
  12: import java.net.MalformedURLException;
  13: import java.util.HashMap;
  14: import java.security.*;
  15: import gnu.gcj.Core;
  16: import java.util.Set;
  17: import java.util.Iterator;
  18: import java.util.HashSet;
  19: import java.util.HashMap;
  20: import java.nio.channels.FileChannel;
  21: import java.io.*;
  22: 
  23: public class SharedLibHelper
  24: {
  25:   /** Load a shared library, and associate a ClassLoader with it.
  26:    * @param libname named of shared library (passed to dlopen)
  27:    * @param parent the parent ClassLoader
  28:    * @parem flags passed to dlopen
  29:    */
  30:   SharedLibHelper(String libname, ClassLoader parent, CodeSource source,
  31:           ProtectionDomain domain, int flags)
  32:   {
  33:     // FIXME: ask security manager first.
  34:     loader = parent;
  35:     baseName = libname;
  36:     if (domain == null)
  37:       domain = new ProtectionDomain(source,
  38:                     Policy.getPolicy().getPermissions(source));
  39:     this.domain = domain;
  40:     this.flags = flags;
  41:   }
  42: 
  43:   public static SharedLibHelper findHelper (String libname)
  44:   {
  45:     synchronized (map)
  46:       {
  47:     Set s = (Set)map.get(libname);
  48:     if (s == null)
  49:       return null;
  50:     for (Iterator i=s.iterator(); i.hasNext();)
  51:       {
  52:         WeakReference ref = (WeakReference)i.next();
  53:         if (ref != null)
  54:           return (SharedLibHelper) ref.get();
  55:       }
  56:     return null;
  57:       }
  58:   }
  59: 
  60:   static void copyFile (File in, File out) throws IOException 
  61:   {
  62:     FileChannel source = new FileInputStream(in).getChannel();
  63:     FileChannel destination = new FileOutputStream(out).getChannel();
  64:     source.transferTo(0, source.size(), destination);
  65:     source.close();
  66:     destination.close();
  67:   }
  68: 
  69:   public static SharedLibHelper findHelper (ClassLoader loader, String libname,
  70:                         CodeSource source,
  71:                         boolean tryParents)
  72:   {
  73:     return findHelper (loader, libname, source, null, tryParents);
  74:   }
  75: 
  76:   public static SharedLibHelper findHelper (ClassLoader loader, String libname,
  77:                         CodeSource source,
  78:                         ProtectionDomain domain, 
  79:                         boolean tryParents)
  80:   {
  81:     synchronized (map)
  82:       {
  83:     SharedLibHelper result;
  84:     Set s = (Set)map.get(libname);
  85:     if (s == null)
  86:       {
  87:         s = new HashSet();
  88:         map.put(libname, s);
  89:       }
  90:     else
  91:       {
  92:         for (Iterator i=s.iterator(); i.hasNext();)
  93:           {
  94:         WeakReference ref = (WeakReference)i.next();
  95:         if (ref != null)
  96:           {
  97:             result = (SharedLibHelper) ref.get();
  98:             if (result != null)
  99:               {            
 100:             // A match succeeds if the library is already
 101:             // loaded by LOADER or any of its ancestors.
 102:             ClassLoader l = loader;
 103:             do
 104:               {
 105:                 if (result.loader == l)
 106:                   return result;
 107:                 l = l.getParent();
 108:               }
 109:             while (tryParents && l != null);
 110:               }
 111:           }
 112:           }
 113: 
 114:         // Oh dear.  We've already mapped this shared library, but
 115:         // with a different class loader.  We need to copy it.
 116:         try
 117:           {
 118:         File copy 
 119:           = File.createTempFile(new File(libname).getName(), 
 120:                     ".so", new File ("/tmp"));
 121:         File src = new File(libname);
 122:         copyFile (src, copy);
 123:         copy.deleteOnExit();
 124:         libname = copy.getPath();
 125:           }
 126:         catch (IOException e)
 127:           {
 128:         return null;
 129:           }
 130:       }
 131:     result = new SharedLibHelper(libname, loader, source, domain, 0);
 132:     s.add(new WeakReference(result));
 133:     return result;
 134:       }
 135:   }
 136: 
 137:   public native void finalize ();
 138: 
 139:   public Class findClass(String name)
 140:   {
 141:     ensureInit();
 142:     Class result = (Class) classMap.get(name);
 143:     if (result != null)
 144:       {
 145:     // We never want to return a class without its supers linked.
 146:     // It isn't clear from the spec, but this is what other
 147:     // implementations do in practice.
 148:     ensureSupersLinked(result);
 149:       }
 150:     return result;
 151:   }
 152: 
 153:   public URL findResource (String name)
 154:   {
 155:     ensureInit();
 156:     if (! hasResource(name))
 157:       return null;
 158:     try
 159:       {
 160:     return new URL("gcjlib", "", -1, baseName + "!/" + name);
 161:       }
 162:     catch (MalformedURLException _)
 163:       {
 164:       }
 165:     return null;
 166:   }
 167: 
 168:   public native Core findCore (String name);
 169: 
 170:   void ensureInit()
 171:   {
 172:     synchronized (classMap)
 173:       {
 174:     if (initialized)
 175:       return;
 176:     init();
 177:     initialized = true;
 178:       }
 179:   }
 180: 
 181:   native boolean hasResource(String name);
 182:   native void init();
 183:   native void ensureSupersLinked(Class k);
 184: 
 185:   public String toString ()
 186:   {
 187:     return "shared object " + baseName;
 188:   }
 189: 
 190:   /** Called during dlopen's processing of the init section. */
 191:   void registerClass(String name, Class cls)
 192:   {
 193:     classMap.put(name, cls);
 194:   }
 195: 
 196:   /** The handle returned by dlopen. */
 197:   gnu.gcj.RawData handler;
 198: 
 199:   /** Holds a _Jv_core_chain for the loader.  */
 200:   gnu.gcj.RawData core_chain;
 201: 
 202:   /** Map classnames to Classes. */
 203:   HashMap classMap = new HashMap(20);
 204: 
 205:   /** Class loader we're helping.  */
 206:   ClassLoader loader;
 207: 
 208:   /** Name of base file.  */
 209:   String baseName;
 210: 
 211:   /** Protection domain for loaded classes.  */
 212:   ProtectionDomain domain;
 213: 
 214:   /** Flags to pass to dlopen.  FIXME: platform dependent.
 215:       0 is always "sensible" (defined by us).  */
 216:   int flags;
 217: 
 218:   /** True if we've been initialized.  */
 219:   boolean initialized = false;
 220: 
 221:   /** Map shared library names to a helper object.  This uses weak
 222:       references in the values so we don't prevent collection.  */
 223:   static HashMap map = new HashMap ();
 224: }