001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.kernel.classloader; 018 019 import java.io.ByteArrayOutputStream; 020 import java.io.IOException; 021 import java.io.InputStream; 022 import java.net.URL; 023 import java.net.URLClassLoader; 024 import java.net.URLStreamHandlerFactory; 025 026 import org.objectweb.asm.ClassReader; 027 import org.objectweb.asm.Opcodes; 028 import org.objectweb.asm.commons.EmptyVisitor; 029 030 /** 031 * ClassLoader implementation that allows classes to be temporarily 032 * loaded and then thrown away. Useful for verifying and inspecting 033 * a class without first loading(and thus polluting) the parent 034 * ClassLoader. 035 * </p> 036 * This class is a proper subclass of URLClassLoader. This class 037 * will locally load any class except for those defined in the 038 * java.*, javax.* and sun.* packages and annotations all of which 039 * are loaded by with 040 * <code>Class.forName(name, resolve, getClass().getClassLoader())</code> 041 * @author Marc Prud'hommeaux 042 */ 043 //Note: this class is a fork from OpenEJB which was a fork from OpenJPA 044 public class TemporaryClassLoader extends URLClassLoader { 045 public TemporaryClassLoader(ClassLoader parent) { 046 super(new URL[0], parent); 047 } 048 049 public TemporaryClassLoader(URL[] urls, ClassLoader parent) { 050 super(urls, parent); 051 } 052 053 public TemporaryClassLoader(URL[] urls) { 054 super(urls); 055 } 056 057 public TemporaryClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { 058 super(urls, parent, factory); 059 } 060 061 public Class loadClass(String name) throws ClassNotFoundException { 062 return loadClass(name, false); 063 } 064 065 protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 066 // see if we've already loaded it 067 Class c = findLoadedClass(name); 068 if (c != null) { 069 return c; 070 } 071 072 // bug #283. defer to system if the name is a protected name. 073 // "sun." is required for JDK 1.4, which has an access check for 074 // sun.reflect.GeneratedSerializationConstructorAccessor1 075 if (name.startsWith("java.") || 076 name.startsWith("javax.") || 077 name.startsWith("sun.")) { 078 return getParent().loadClass(name); 079 } 080 081 String resourceName = name.replace('.', '/') + ".class"; 082 InputStream in = getResourceAsStream(resourceName); 083 if (in == null) { 084 throw new ClassNotFoundException(name); 085 } 086 087 // 80% of class files are smaller then 6k 088 ByteArrayOutputStream bout = new ByteArrayOutputStream(8 * 1024); 089 090 // copy the input stream into a byte array 091 byte[] bytes = new byte[0]; 092 try { 093 byte[] buf = new byte[4 * 1024]; 094 for (int count = -1; (count = in.read(buf)) >= 0;) { 095 bout.write(buf, 0, count); 096 } 097 bytes = bout.toByteArray(); 098 } catch (IOException e) { 099 throw new ClassNotFoundException(name, e); 100 } 101 102 // Annotation classes must be loaded by the normal classloader 103 if (isAnnotationClass(bytes)) { 104 return Class.forName(name, resolve, getClass().getClassLoader()); 105 } 106 107 // define the package 108 int packageEndIndex = name.lastIndexOf('.'); 109 if (packageEndIndex != -1) { 110 String packageName = name.substring(0, packageEndIndex); 111 if (getPackage(packageName) == null) { 112 definePackage(packageName, null, null, null, null, null, null, null); 113 } 114 } 115 116 // define the class 117 try { 118 return defineClass(name, bytes, 0, bytes.length); 119 } catch (SecurityException e) { 120 // possible prohibited package: defer to the parent 121 return super.loadClass(name, resolve); 122 } 123 } 124 125 /** 126 * Fast-parse the given class bytecode to determine if it is an 127 * annotation class. 128 */ 129 private static boolean isAnnotationClass(byte[] bytes) { 130 IsAnnotationVisitor isAnnotationVisitor = new IsAnnotationVisitor(); 131 ClassReader classReader = new ClassReader(bytes); 132 classReader.accept(isAnnotationVisitor, true); 133 return isAnnotationVisitor.isAnnotation; 134 } 135 136 public static class IsAnnotationVisitor extends EmptyVisitor { 137 public boolean isAnnotation = false; 138 139 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 140 isAnnotation = (access & Opcodes.ACC_ANNOTATION) != 0; 141 } 142 143 } 144 } 145