1 /* InstrumentationImpl.java -- GNU implementation of 2 java.lang.instrument.Instrumentation 3 Copyright (C) 2005, 2006 Free Software Foundation, Inc. 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 gnu.java.lang; 41 42 import java.lang.instrument.Instrumentation; 43 import java.lang.instrument.ClassFileTransformer; 44 import java.lang.instrument.ClassDefinition; 45 import java.lang.instrument.UnmodifiableClassException; 46 import java.lang.instrument.IllegalClassFormatException; 47 48 import java.security.ProtectionDomain; 49 50 import java.util.ArrayList; 51 import java.util.Iterator; 52 53 /** 54 * An Instrumentation object has transformers that will 55 * be called each time a class is defined or redefined. 56 * The object is given to a <code>premain</code> function 57 * that is called before the <code>main</code> function. 58 * 59 * @author Nicolas Geoffray (nicolas.geoffray@menlina.com) 60 * @since 1.5 61 */ 62 public final class InstrumentationImpl implements Instrumentation 63 { 64 65 /* List of transformers */ 66 private ArrayList<ClassFileTransformer> transformers = 67 new ArrayList<ClassFileTransformer>(); 68 69 InstrumentationImpl()70 InstrumentationImpl() 71 { 72 } 73 74 /** 75 * Adds a <code>ClassFileTransformer</class> object 76 * to the instrumentation. Each time a class is defined 77 * or redefined, the <code>transform</code> method of the 78 * <code>transformer</code> object is called. 79 * 80 * @param transformer the transformer to add 81 * @throws NullPointerException if transformer is null 82 */ addTransformer(ClassFileTransformer transformer)83 public void addTransformer(ClassFileTransformer transformer) 84 { 85 if (transformer == null) 86 throw new NullPointerException(); 87 synchronized(transformers) 88 { 89 transformers.add(transformer); 90 } 91 } 92 93 /** 94 * Removes the given transformer from the set of transformers 95 * this Instrumentation object has. 96 * 97 * @param transformer the transformer to remove 98 * @return true if the transformer was found and removed, false if 99 * the transformer was not found 100 * @throws NullPointerException if transformer is null 101 */ removeTransformer(ClassFileTransformer transformer)102 public boolean removeTransformer(ClassFileTransformer transformer) 103 { 104 if (transformer == null) 105 throw new NullPointerException(); 106 107 boolean result; 108 synchronized (transformers) 109 { 110 result = transformers.remove(transformer); 111 } 112 return result; 113 } 114 115 /** 116 * Returns if the current JVM supports class redefinition 117 * 118 * @return true if the current JVM supports class redefinition 119 */ isRedefineClassesSupported()120 public boolean isRedefineClassesSupported() 121 { 122 return VMInstrumentationImpl.isRedefineClassesSupported(); 123 } 124 125 /** 126 * Redefine classes present in the definitions array, with 127 * the corresponding class files. 128 * 129 * @param definitions an array of classes to redefine 130 * 131 * @throws ClassNotFoundException if a class cannot be found 132 * @throws UnmodifiableClassException if a class cannot be modified 133 * @throws UnsupportedOperationException if the JVM does not support 134 * redefinition or the redefinition made unsupported changes 135 * @throws ClassFormatError if a class file is not valid 136 * @throws NoClassDefFoundError if a class name is not equal to the name 137 * in the class file specified 138 * @throws UnsupportedClassVersionError if the class file version numbers 139 * are unsupported 140 * @throws ClassCircularityError if circularity occured with the new 141 * classes 142 * @throws LinkageError if a linkage error occurs 143 * @throws NullPointerException if the definitions array is null, or any 144 * of its element 145 * 146 * @see isRedefineClassesSupported() 147 * @see addTransformer(java.lang.instrument.ClassFileTransformer) 148 * @see ClassFileTransformer 149 */ redefineClasses(ClassDefinition[] definitions)150 public void redefineClasses(ClassDefinition[] definitions) 151 throws ClassNotFoundException, 152 UnmodifiableClassException 153 { 154 if (!isRedefineClassesSupported()) 155 throw new UnsupportedOperationException(); 156 157 VMInstrumentationImpl.redefineClasses(this, definitions); 158 } 159 160 161 /** 162 * Get all the classes loaded by the JVM. 163 * 164 * @return an array containing all the classes loaded by the JVM. The array 165 * is empty if no class is loaded. 166 */ getAllLoadedClasses()167 public Class[] getAllLoadedClasses() 168 { 169 return VMInstrumentationImpl.getAllLoadedClasses(); 170 } 171 172 /** 173 * Get all the classes loaded by a given class loader 174 * 175 * @param loader the loader 176 * 177 * @return an array containing all the classes loaded by the given loader. 178 * The array is empty if no class was loaded by the loader. 179 */ getInitiatedClasses(ClassLoader loader)180 public Class[] getInitiatedClasses(ClassLoader loader) 181 { 182 return VMInstrumentationImpl.getInitiatedClasses(loader); 183 } 184 185 /** 186 * Get the size of an object. 187 * 188 * @param objectToSize the object 189 * @return the size of the object 190 * @throws NullPointerException if objectToSize is null. 191 */ getObjectSize(Object objectToSize)192 public long getObjectSize(Object objectToSize) 193 { 194 // We alleviate the VM work 195 if (objectToSize == null) 196 throw new NullPointerException(); 197 return VMInstrumentationImpl.getObjectSize(objectToSize); 198 } 199 200 /** 201 * Called by the VM or redefineClasses to call each transformer 202 * 203 * @param loader the loader of the class 204 * @param className the name of the class with packages separated with "/" 205 * @param classBeingRedefined the class being redefined if it's the case, 206 * null otherwise 207 * @param protectionDomain the protection domain of the class being defined 208 * or redefined 209 * @param classfileBuffer the input byte buffer in class file format 210 * 211 * @return the new class file 212 */ callTransformers(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)213 public byte[] callTransformers(ClassLoader loader, String className, 214 Class<?> classBeingRedefined, ProtectionDomain protectionDomain, 215 byte[] classfileBuffer) 216 { 217 byte[] newBuffer = null; 218 byte[] oldBuffer = classfileBuffer; 219 ClassFileTransformer current; 220 synchronized (transformers) 221 { 222 Iterator<ClassFileTransformer> i = transformers.iterator(); 223 while (i.hasNext()) 224 { 225 current = i.next(); 226 try 227 { 228 newBuffer = current.transform(loader, className, 229 classBeingRedefined, protectionDomain, oldBuffer); 230 } 231 catch (IllegalClassFormatException ignored) 232 { 233 //IGNORED 234 } 235 if (newBuffer != null) 236 oldBuffer = newBuffer; 237 } 238 } 239 return oldBuffer; 240 } 241 } 242