1 /* VMClassLoader.java -- Reference implementation of native interface
2    required by ClassLoader
3    Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 package java.lang;
40 
41 import gnu.java.util.EmptyEnumeration;
42 import java.lang.reflect.Constructor;
43 import java.io.File;
44 import java.io.IOException;
45 import java.net.URL;
46 import java.net.URLClassLoader;
47 import java.security.AllPermission;
48 import java.security.Permission;
49 import java.security.Permissions;
50 import java.security.ProtectionDomain;
51 import java.util.ArrayList;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.Map;
56 import java.util.StringTokenizer;
57 import gnu.gcj.runtime.BootClassLoader;
58 
59 /**
60  * java.lang.VMClassLoader is a package-private helper for VMs to implement
61  * on behalf of java.lang.ClassLoader.
62  *
63  * @author John Keiser
64  * @author Mark Wielaard <mark@klomp.org>
65  * @author Eric Blake <ebb9@email.byu.edu>
66  */
67 final class VMClassLoader
68 {
69   // Protection Domain definitions
70   // FIXME: should there be a special protection domain used for native code?
71 
72   // The permission required to check what a classes protection domain is.
73   static final Permission protectionDomainPermission
74     = new RuntimePermission("getProtectionDomain");
75   // The protection domain returned if we cannot determine it.
76   static ProtectionDomain unknownProtectionDomain;
77 
78   static
79   {
80     Permissions permissions = new Permissions();
permissions.add(new AllPermission())81     permissions.add(new AllPermission());
82     unknownProtectionDomain = new ProtectionDomain(null, permissions);
83   }
84 
85   static final HashMap definedPackages = new HashMap();
86 
87   // This is a helper for handling java.endorsed.dirs.  It is null
88   // until we've initialized the system, at which point it is created.
89   static BootClassLoader bootLoader;
90 
91   // This keeps track of shared libraries we've already tried to load.
92   private static HashSet tried_libraries;
93 
94   // Holds one of the LIB_* constants; used to determine how shared
95   // library loads are done.
96   private static int lib_control;
97 
98   private static final int LIB_FULL = 0;
99   private static final int LIB_CACHE = 1;
100   private static final int LIB_NEVER = 2;
101 
102   /**
103    * Helper to define a class using a string of bytes. This assumes that
104    * the security checks have already been performed, if necessary.
105    *
106    * <strong>For backward compatibility, this just ignores the protection
107    * domain; that is the wrong behavior, and you should directly implement
108    * this method natively if you can.</strong>
109    *
110    * @param name the name to give the class, or null if unknown
111    * @param data the data representing the classfile, in classfile format
112    * @param offset the offset into the data where the classfile starts
113    * @param len the length of the classfile data in the array
114    * @param pd the protection domain
115    * @return the class that was defined
116    * @throws ClassFormatError if data is not in proper classfile format
117    */
defineClass(ClassLoader cl, String name, byte[] data, int offset, int len, ProtectionDomain pd)118   static final native Class defineClass(ClassLoader cl, String name,
119 					byte[] data, int offset, int len,
120 					ProtectionDomain pd)
121     throws ClassFormatError;
122 
123   /**
124    * Helper to resolve all references to other classes from this class.
125    *
126    * @param c the class to resolve
127    */
resolveClass(Class clazz)128   static final void resolveClass(Class clazz)
129   {
130     // There doesn't seem to be a need for this to do anything.
131     // Testing reveals that the JDK doesn't seem to do anything here,
132     // either.
133   }
134 
135   /**
136    * Helper to load a class from the bootstrap class loader.
137    *
138    * @param name the class name to load
139    * @param resolve whether to resolve it
140    * @return the class, loaded by the bootstrap classloader or null
141    * if the class wasn't found. Returning null is equivalent to throwing
142    * a ClassNotFoundException (but a possible performance optimization).
143    */
loadClass(String name, boolean resolve)144   static final native Class loadClass(String name, boolean resolve)
145     throws ClassNotFoundException;
146 
147   /**
148    * Helper to load a resource from the bootstrap class loader.
149    *
150    * In libgcj, this does nothing, as the default system loader knows
151    * how to find resources that have been linked in.
152    *
153    * @param name the resource to find
154    * @return the URL to the resource
155    */
getResource(String name)156   static URL getResource(String name)
157   {
158     if (bootLoader != null)
159       return bootLoader.bootGetResource(name);
160     return null;
161   }
162 
163   /**
164    * Helper to get a list of resources from the bootstrap class loader.
165    *
166    * In libgcj, this does nothing, as the default system loader knows
167    * how to find resources that have been linked in.
168    *
169    * @param name the resource to find
170    * @return an enumeration of resources
171    * @throws IOException if one occurs
172    */
getResources(String name)173   static Enumeration getResources(String name) throws IOException
174   {
175     if (bootLoader != null)
176       return bootLoader.bootGetResources(name);
177     return EmptyEnumeration.getInstance();
178   }
179 
180   /**
181    * Helper to get a package from the bootstrap class loader.  The default
182    * implementation of returning null may be adequate, or you may decide
183    * that this needs some native help.
184    *
185    * @param name the name to find
186    * @return the named package, if it exists
187    */
getPackage(String name)188   static synchronized Package getPackage(String name)
189   {
190     return (Package) definedPackages.get(name);
191   }
192 
193   /**
194    * Helper to get all packages from the bootstrap class loader.  The default
195    * implementation of returning an empty array may be adequate, or you may
196    * decide that this needs some native help.
197    *
198    * @return all named packages, if any exist
199    */
getPackages()200   static synchronized Package[] getPackages()
201   {
202     Package[] packages = new Package[definedPackages.size()];
203     return (Package[]) definedPackages.values().toArray(packages);
204   }
205 
206   // Define a package for something loaded natively.
definePackageForNative(String className)207   static synchronized void definePackageForNative(String className)
208   {
209     int lastDot = className.lastIndexOf('.');
210     if (lastDot != -1)
211       {
212 	String packageName = className.substring(0, lastDot);
213 	if (getPackage(packageName) == null)
214 	  {
215 	    // FIXME: this assumes we're defining the core, which
216 	    // isn't necessarily so.  We could detect this and set up
217 	    // appropriately.  We could also look at a manifest file
218 	    // compiled into the .so.
219 	    Package p = new Package(packageName,
220 				    "Java Platform API Specification",
221 				    "GNU", "1.4", "gcj", "GNU",
222 				    null, // FIXME: gcj version.
223 				    null);
224 	    definedPackages.put(packageName, p);
225 	  }
226       }
227   }
228 
229   /**
230    * Helper for java.lang.Integer, Byte, etc to get the TYPE class
231    * at initialization time. The type code is one of the chars that
232    * represents the primitive type as in JNI.
233    *
234    * <ul>
235    * <li>'Z' - boolean</li>
236    * <li>'B' - byte</li>
237    * <li>'C' - char</li>
238    * <li>'D' - double</li>
239    * <li>'F' - float</li>
240    * <li>'I' - int</li>
241    * <li>'J' - long</li>
242    * <li>'S' - short</li>
243    * <li>'V' - void</li>
244    * </ul>
245    *
246    * @param type the primitive type
247    * @return a "bogus" class representing the primitive type
248    */
getPrimitiveClass(char type)249   static final native Class getPrimitiveClass(char type);
250 
251   /**
252    * The system default for assertion status. This is used for all system
253    * classes (those with a null ClassLoader), as well as the initial value for
254    * every ClassLoader's default assertion status.
255    *
256    * XXX - Not implemented yet; this requires native help.
257    *
258    * @return the system-wide default assertion status
259    */
defaultAssertionStatus()260   static final boolean defaultAssertionStatus()
261   {
262     return true;
263   }
264 
265   /**
266    * The system default for package assertion status. This is used for all
267    * ClassLoader's packageAssertionStatus defaults. It must be a map of
268    * package names to Boolean.TRUE or Boolean.FALSE, with the unnamed package
269    * represented as a null key.
270    *
271    * XXX - Not implemented yet; this requires native help.
272    *
273    * @return a (read-only) map for the default packageAssertionStatus
274    */
packageAssertionStatus()275   static final Map packageAssertionStatus()
276   {
277     return new HashMap();
278   }
279 
280   /**
281    * The system default for class assertion status. This is used for all
282    * ClassLoader's classAssertionStatus defaults. It must be a map of
283    * class names to Boolean.TRUE or Boolean.FALSE
284    *
285    * XXX - Not implemented yet; this requires native help.
286    *
287    * @return a (read-only) map for the default classAssertionStatus
288    */
classAssertionStatus()289   static final Map classAssertionStatus()
290   {
291     return new HashMap();
292   }
293 
getSystemClassLoaderInternal()294   static native ClassLoader getSystemClassLoaderInternal();
295 
initBootLoader(String libdir)296   static native void initBootLoader(String libdir);
297 
initialize(String libdir)298   static void initialize(String libdir)
299   {
300     initBootLoader(libdir);
301 
302     String p
303       = System.getProperty ("gnu.gcj.runtime.VMClassLoader.library_control",
304 			    "");
305     if ("never".equals(p))
306       lib_control = LIB_NEVER;
307     else if ("cache".equals(p))
308       lib_control = LIB_CACHE;
309     else if ("full".equals(p))
310       lib_control = LIB_FULL;
311     else
312       lib_control = LIB_NEVER;
313 
314     tried_libraries = new HashSet();
315   }
316 
317   /**
318    * Possibly load a .so and search it for classes.
319    */
nativeFindClass(String name)320   static native Class nativeFindClass(String name);
321 
getSystemClassLoader()322   static ClassLoader getSystemClassLoader()
323   {
324     // This method is called as the initialization of systemClassLoader,
325     // so if there is a null value, this is the first call and we must check
326     // for java.system.class.loader.
327     String loader = System.getProperty("java.system.class.loader");
328     ClassLoader default_sys = getSystemClassLoaderInternal();
329     if (loader != null)
330       {
331 	try
332 	  {
333 	    Class load_class = Class.forName(loader, true, default_sys);
334 	    Constructor c
335 	      = load_class.getConstructor(new Class[] { ClassLoader.class });
336 	    default_sys
337 	      = (ClassLoader) c.newInstance(new Object[] { default_sys });
338 	  }
339 	catch (Exception ex)
340 	  {
341 	    throw new Error("Failed to load requested system classloader "
342 			       + loader, ex);
343 	  }
344       }
345 
346     return default_sys;
347   }
348 }
349