1 /* VMClassLoader.java -- Reference implementation of native interface
2 required by ClassLoader
3 Copyright (C) 1998, 2001, 2002, 2004, 2005, 2006 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
40 package java.lang;
41
42 import gnu.classpath.Configuration;
43 import gnu.classpath.SystemProperties;
44 import gnu.java.lang.InstrumentationImpl;
45
46 import java.io.BufferedReader;
47 import java.io.File;
48 import java.io.IOException;
49 import java.io.InputStreamReader;
50 import java.lang.instrument.Instrumentation;
51 import java.net.MalformedURLException;
52 import java.net.URL;
53 import java.security.ProtectionDomain;
54 import java.util.Enumeration;
55 import java.util.HashMap;
56 import java.util.HashSet;
57 import java.util.Map;
58 import java.util.Set;
59 import java.util.StringTokenizer;
60 import java.util.Vector;
61 import java.util.zip.ZipFile;
62
63 /**
64 * java.lang.VMClassLoader is a package-private helper for VMs to implement
65 * on behalf of java.lang.ClassLoader.
66 *
67 * @author John Keiser
68 * @author Mark Wielaard (mark@klomp.org)
69 * @author Eric Blake (ebb9@email.byu.edu)
70 */
71 final class VMClassLoader
72 {
73
74
75 /** packages loaded by the bootstrap class loader */
76 static final HashMap definedPackages = new HashMap();
77
78 /**
79 * Converts the array string of native package names to
80 * Packages. The packages are then put into the
81 * definedPackages hashMap
82 */
83 static
84 {
85 String[] packages = getBootPackages();
86
87 if( packages != null)
88 {
89 String specName =
90 SystemProperties.getProperty("java.specification.name");
91 String vendor =
92 SystemProperties.getProperty("java.specification.vendor");
93 String version =
94 SystemProperties.getProperty("java.specification.version");
95
96 Package p;
97
98 for(int i = 0; i < packages.length; i++)
99 {
100 p = new Package(packages[i],
101 specName,
102 vendor,
103 version,
104 "GNU Classpath",
105 "GNU",
106 Configuration.CLASSPATH_VERSION,
107 null,
108 null);
109
110 definedPackages.put(packages[i], p);
111 }
112 }
113 }
114
115
116 /**
117 * Helper to define a class using a string of bytes. This assumes that
118 * the security checks have already been performed, if necessary.
119 *
120 * Implementations of this method are advised to consider the
121 * situation where user code modifies the byte array after it has
122 * been passed to defineClass. This can be handled by making a
123 * private copy of the array, or arranging to only read any given
124 * byte a single time.
125 *
126 * @param name the name to give the class, or null if unknown
127 * @param data the data representing the classfile, in classfile format
128 * @param offset the offset into the data where the classfile starts
129 * @param len the length of the classfile data in the array
130 * @param pd the protection domain
131 * @return the class that was defined
132 * @throws ClassFormatError if data is not in proper classfile format
133 */
134 static final native Class defineClass(ClassLoader cl, String name,
135 byte[] data, int offset, int len,
136 ProtectionDomain pd)
137 throws ClassFormatError;
138
139 /**
140 * Helper to resolve all references to other classes from this class.
141 *
142 * @param c the class to resolve
143 */
144 static final native void resolveClass(Class c);
145
146 /**
147 * Helper to load a class from the bootstrap class loader.
148 *
149 * @param name the class name to load
150 * @param resolve whether to resolve it
151 * @return the class, loaded by the bootstrap classloader or null
152 * if the class wasn't found. Returning null is equivalent to throwing
153 * a ClassNotFoundException (but a possible performance optimization).
154 */
155 static final native Class loadClass(String name, boolean resolve)
156 throws ClassNotFoundException;
157
158 /**
159 * Helper to load a resource from the bootstrap class loader.
160 *
161 * @param name the resource to find
162 * @return the URL to the resource
163 */
164 static URL getResource(String name)
165 {
166 Enumeration e = getResources(name);
167 if (e.hasMoreElements())
168 return (URL)e.nextElement();
169 return null;
170 }
171
172 /** jars from property java.boot.class.path */
173 static final HashMap bootjars = new HashMap();
174
175 /**
176 * Helper to get a list of resources from the bootstrap class loader.
177 *
178 * @param name the resource to find
179 * @return an enumeration of resources
180 */
181 static Enumeration getResources(String name)
182 {
183 StringTokenizer st = new StringTokenizer(
184 SystemProperties.getProperty("java.boot.class.path", "."),
185 File.pathSeparator);
186 Vector v = new Vector();
187 while (st.hasMoreTokens())
188 {
189 File file = new File(st.nextToken());
190 if (file.isDirectory())
191 {
192 try
193 {
194 File f = new File(file, name);
195 if (!f.exists()) continue;
196 v.add(new URL("file://" + f.getAbsolutePath()));
197 }
198 catch (MalformedURLException e)
199 {
200 throw new Error(e);
201 }
202 }
203 else if (file.isFile())
204 {
205 ZipFile zip;
206 synchronized(bootjars)
207 {
208 zip = (ZipFile) bootjars.get(file.getName());
209 }
210 if(zip == null)
211 {
212 try
213 {
214 zip = new ZipFile(file);
215 synchronized(bootjars)
216 {
217 bootjars.put(file.getName(), zip);
218 }
219 }
220 catch (IOException e)
221 {
222 continue;
223 }
224 }
225 String zname = name.startsWith("/") ? name.substring(1) : name;
226 if (zip.getEntry(zname) == null)
227 continue;
228 try
229 {
230 v.add(new URL("jar:file://"
231 + file.getAbsolutePath() + "!/" + zname));
232 }
233 catch (MalformedURLException e)
234 {
235 throw new Error(e);
236 }
237 }
238 }
239 return v.elements();
240 }
241
242
243 /**
244 * Returns a String[] of native package names. The default
245 * implementation tries to load a list of package from
246 * the META-INF/INDEX.LIST file in the boot jar file.
247 * If not found or if any exception is raised, it returns
248 * an empty array. You may decide this needs native help.
249 */
250 private static String[] getBootPackages()
251 {
252 URL indexList = getResource("META-INF/INDEX.LIST");
253 if (indexList != null)
254 {
255 try
256 {
257 Set packageSet = new HashSet();
258 String line;
259 int lineToSkip = 3;
260 BufferedReader reader = new BufferedReader(
261 new InputStreamReader(
262 indexList.openStream()));
263 while ((line = reader.readLine()) != null)
264 {
265 if (lineToSkip == 0)
266 {
267 if (line.length() == 0)
268 lineToSkip = 1;
269 else
270 packageSet.add(line.replace('/', '.'));
271 }
272 else
273 lineToSkip--;
274 }
275 reader.close();
276 return (String[]) packageSet.toArray(new String[packageSet.size()]);
277 }
278 catch (IOException e)
279 {
280 return new String[0];
281 }
282 }
283 else
284 return new String[0];
285 }
286
287
288 /**
289 * Helper to get a package from the bootstrap class loader.
290 *
291 * @param name the name to find
292 * @return the named package, if it exists
293 */
294 static Package getPackage(String name)
295 {
296 return (Package)definedPackages.get(name);
297 }
298
299
300
301 /**
302 * Helper to get all packages from the bootstrap class loader.
303 *
304 * @return all named packages, if any exist
305 */
306 static Package[] getPackages()
307 {
308 Package[] packages = new Package[definedPackages.size()];
309 definedPackages.values().toArray(packages);
310 return packages;
311 }
312
313 /**
314 * Helper for java.lang.Integer, Byte, etc to get the TYPE class
315 * at initialization time. The type code is one of the chars that
316 * represents the primitive type as in JNI.
317 *
318 * <ul>
319 * <li>'Z' - boolean</li>
320 * <li>'B' - byte</li>
321 * <li>'C' - char</li>
322 * <li>'D' - double</li>
323 * <li>'F' - float</li>
324 * <li>'I' - int</li>
325 * <li>'J' - long</li>
326 * <li>'S' - short</li>
327 * <li>'V' - void</li>
328 * </ul>
329 *
330 * @param type the primitive type
331 * @return a "bogus" class representing the primitive type
332 */
333 static final native Class getPrimitiveClass(char type);
334
335 /**
336 * The system default for assertion status. This is used for all system
337 * classes (those with a null ClassLoader), as well as the initial value for
338 * every ClassLoader's default assertion status.
339 *
340 * XXX - Not implemented yet; this requires native help.
341 *
342 * @return the system-wide default assertion status
343 */
344 static final boolean defaultAssertionStatus()
345 {
346 return true;
347 }
348
349 /**
350 * The system default for package assertion status. This is used for all
351 * ClassLoader's packageAssertionStatus defaults. It must be a map of
352 * package names to Boolean.TRUE or Boolean.FALSE, with the unnamed package
353 * represented as a null key.
354 *
355 * XXX - Not implemented yet; this requires native help.
356 *
357 * @return a (read-only) map for the default packageAssertionStatus
358 */
359 static final Map packageAssertionStatus()
360 {
361 return new HashMap();
362 }
363
364 /**
365 * The system default for class assertion status. This is used for all
366 * ClassLoader's classAssertionStatus defaults. It must be a map of
367 * class names to Boolean.TRUE or Boolean.FALSE
368 *
369 * XXX - Not implemented yet; this requires native help.
370 *
371 * @return a (read-only) map for the default classAssertionStatus
372 */
373 static final Map classAssertionStatus()
374 {
375 return new HashMap();
376 }
377
378 static ClassLoader getSystemClassLoader()
379 {
380 return ClassLoader.defaultGetSystemClassLoader();
381 }
382
383 /**
384 * Find the class if this class loader previously defined this class
385 * or if this class loader has been recorded as the initiating class loader
386 * for this class.
387 */
388 static native Class findLoadedClass(ClassLoader cl, String name);
389
390 /**
391 * The Instrumentation object created by the vm when agents are defined.
392 */
393 static final Instrumentation instrumenter = null;
394
395 /**
396 * Call the transformers of the possible Instrumentation object. This
397 * implementation assumes the instrumenter is a
398 * <code>InstrumentationImpl</code> object. VM implementors would
399 * have to redefine this method if they provide their own implementation
400 * of the <code>Instrumentation</code> interface.
401 *
402 * @param loader the initiating loader
403 * @param name the name of the class
404 * @param data the data representing the classfile, in classfile format
405 * @param offset the offset into the data where the classfile starts
406 * @param len the length of the classfile data in the array
407 * @param pd the protection domain
408 * @return the new data representing the classfile
409 */
410 static final Class defineClassWithTransformers(ClassLoader loader,
411 String name, byte[] data, int offset, int len, ProtectionDomain pd)
412 {
413
414 if (instrumenter != null)
415 {
416 byte[] modifiedData = new byte[len];
417 System.arraycopy(data, offset, modifiedData, 0, len);
418 modifiedData =
419 ((InstrumentationImpl)instrumenter).callTransformers(loader, name,
420 null, pd, modifiedData);
421
422 return defineClass(loader, name, modifiedData, 0, modifiedData.length,
423 pd);
424 }
425 else
426 {
427 return defineClass(loader, name, data, offset, len, pd);
428 }
429 }
430 }