// Tags: JDK1.1 // Copyright (C) 2005 Free Software Foundation, Inc. // Written by Jeroen Frijters <jeroen@frijters.net> // This file is part of Mauve. // Mauve is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2, or (at your option) // any later version. // Mauve is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Mauve; see the file COPYING. If not, write to // the Free Software Foundation, 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. */ package gnu.testlet.wonka.lang.ClassLoader; import gnu.testlet.TestHarness; import gnu.testlet.Testlet; public class findLoadedClass extends ClassLoader implements Testlet { // This represents the class: // class Triv extends java.util.Hashtable {} private static byte[] trivialClassDef = { (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x2D, (byte)0x00, (byte)0x0F, (byte)0x07, (byte)0x00, (byte)0x0C, (byte)0x07, (byte)0x00, (byte)0x0E, (byte)0x0A, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x0C, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x00, (byte)0x03, (byte)0x28, (byte)0x29, (byte)0x56, (byte)0x01, (byte)0x00, (byte)0x06, (byte)0x3C, (byte)0x69, (byte)0x6E, (byte)0x69, (byte)0x74, (byte)0x3E, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x43, (byte)0x6F, (byte)0x64, (byte)0x65, (byte)0x01, (byte)0x00, (byte)0x0D, (byte)0x43, (byte)0x6F, (byte)0x6E, (byte)0x73, (byte)0x74, (byte)0x61, (byte)0x6E, (byte)0x74, (byte)0x56, (byte)0x61, (byte)0x6C, (byte)0x75, (byte)0x65, (byte)0x01, (byte)0x00, (byte)0x0A, (byte)0x45, (byte)0x78, (byte)0x63, (byte)0x65, (byte)0x70, (byte)0x74, (byte)0x69, (byte)0x6F, (byte)0x6E, (byte)0x73, (byte)0x01, (byte)0x00, (byte)0x0E, (byte)0x4C, (byte)0x6F, (byte)0x63, (byte)0x61, (byte)0x6C, (byte)0x56, (byte)0x61, (byte)0x72, (byte)0x69, (byte)0x61, (byte)0x62, (byte)0x6C, (byte)0x65, (byte)0x73, (byte)0x01, (byte)0x00, (byte)0x0A, (byte)0x53, (byte)0x6F, (byte)0x75, (byte)0x72, (byte)0x63, (byte)0x65, (byte)0x46, (byte)0x69, (byte)0x6C, (byte)0x65, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x54, (byte)0x72, (byte)0x69, (byte)0x76, (byte)0x01, (byte)0x00, (byte)0x09, (byte)0x54, (byte)0x72, (byte)0x69, (byte)0x76, (byte)0x2E, (byte)0x6A, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x01, (byte)0x00, (byte)0x13, (byte)0x6A, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2F, (byte)0x75, (byte)0x74, (byte)0x69, (byte)0x6C, (byte)0x2F, (byte)0x48, (byte)0x61, (byte)0x73, (byte)0x68, (byte)0x74, (byte)0x61, (byte)0x62, (byte)0x6C, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x2A, (byte)0xB7, (byte)0x00, (byte)0x03, (byte)0xB1, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x0B, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x0D }; private boolean broken; public findLoadedClass() { } protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { if (broken) throw new ClassNotFoundException(); else return super.loadClass(name, resolve); } private findLoadedClass(ClassLoader parent) { super(parent); } public void test(TestHarness harness) { defineClass("Triv", trivialClassDef, 0, trivialClassDef.length); // defineClass should have registered the class harness.checkPoint("defineClass should register"); checkLoaded(harness, this, "Triv"); // make sure that the VM registers the initiating class loader harness.checkPoint("VM should register"); checkLoaded(harness, this, "java.util.Hashtable"); // types that weren't loaded shouldn't be visible harness.checkPoint("premature"); harness.check(findLoadedClass("java.lang.Object") == null); // Class.forName() should register the initiating loader. harness.checkPoint("Class.forName"); try { Class.forName("java.lang.Object", false, this); } catch(ClassNotFoundException x) { harness.debug(x); } checkLoaded(harness, this, "java.lang.Object"); // The above should also apply to arrays // Note that on Sun JDK 1.4 (not on 1.5), loading the component type // also make the array type visible, so we don't test that the array // is not visible at this point. try { Class.forName("[Ljava.lang.Object;", false, this); } catch(ClassNotFoundException x) { harness.debug(x); } checkLoaded(harness, this, "[Ljava.lang.Object;"); // Loading an array type, makes available the ultimate component type harness.checkPoint("array implies component type"); harness.check(findLoadedClass("java.util.Vector") == null); try { Class.forName("[[Ljava.util.Vector;", false, this); } catch(ClassNotFoundException x) { harness.debug(x); } checkLoaded(harness, this, "java.util.Vector"); // After loading a class thru a parent, we shouldn't be able to define it. harness.checkPoint("no redefine"); findLoadedClass cl = new findLoadedClass(this); harness.check(cl.findLoadedClass("Triv") == null); try { Class.forName("Triv", false, cl); } catch(ClassNotFoundException x) { harness.debug(x); throw new Error(x); } checkLoaded(harness, cl, "Triv"); try { cl.defineClass("Triv", trivialClassDef, 0, trivialClassDef.length); harness.check(false, "Don't load it !"); } catch(LinkageError _) { harness.check(true); } // Check multi level trickery harness.checkPoint("multi level"); findLoadedClass grandParent = new findLoadedClass(); grandParent.defineClass("Triv", trivialClassDef, 0, trivialClassDef.length); findLoadedClass parent = new findLoadedClass(grandParent); findLoadedClass child = new findLoadedClass(parent); try { Class.forName("Triv", false, child); } catch(ClassNotFoundException x) { harness.debug(x); throw new Error(x); } try { parent.defineClass("Triv", trivialClassDef, 0, trivialClassDef.length); harness.check(true); } catch(LinkageError x) { harness.debug(x); harness.check(false); } try { Class c = Class.forName("Triv", false, child); harness.check(c.getClassLoader() == grandParent); } catch(ClassNotFoundException x) { harness.debug(x); harness.check(false); } catch(LinkageError x) { harness.debug(x); harness.check(false); } // Even if a class loader is broken, Class.forName() should continue // to work. child.broken = true; try { Class c = Class.forName("Triv", false, child); harness.check(c.getClassLoader() , grandParent, "grandParentCheck"); } catch(ClassNotFoundException x) { harness.debug(x); harness.check(false); } catch(LinkageError x) { harness.debug(x); harness.check(false); } // The VM should also look in the loaded classes cache, before calling loadClass() harness.checkPoint("VM consults cache"); findLoadedClass newLoader = new findLoadedClass(); try { Class.forName("java.util.Hashtable", false, newLoader); } catch(ClassNotFoundException x) { harness.debug(x); throw new Error(x); } newLoader.broken = true; newLoader.defineClass("Triv", trivialClassDef, 0, trivialClassDef.length); } private void checkLoaded(TestHarness harness, findLoadedClass cl, String name) { Class c = cl.findLoadedClass(name); harness.check(c != null,name +" is loaded"); if(c != null) { harness.check(c.getName(),name, "check name "+name); } } }