1 16 17 package org.springframework.instrument.classloading.tomcat; 18 19 import java.lang.instrument.ClassFileTransformer ; 20 import java.lang.reflect.Field ; 21 import java.lang.reflect.Modifier ; 22 23 import org.apache.catalina.loader.ResourceEntry; 24 import org.apache.catalina.loader.WebappClassLoader; 25 26 import org.springframework.instrument.classloading.WeavingTransformer; 27 28 57 public class TomcatInstrumentableClassLoader extends WebappClassLoader { 58 59 60 private final WeavingTransformer weavingTransformer; 61 62 63 public TomcatInstrumentableClassLoader() { 64 super(); 65 this.weavingTransformer = new WeavingTransformer(); 66 } 67 68 public TomcatInstrumentableClassLoader(ClassLoader classLoader) { 69 super(classLoader); 70 this.weavingTransformer = new WeavingTransformer(classLoader); 71 } 72 73 74 80 public void addTransformer(ClassFileTransformer transformer) { 81 this.weavingTransformer.addTransformer(transformer); 82 } 83 84 90 public ClassLoader getThrowawayClassLoader() { 91 WebappClassLoader tempLoader = new WebappClassLoader(); 92 shallowCopyFieldState(this, tempLoader); 95 return tempLoader; 96 } 97 98 99 @Override 100 protected ResourceEntry findResourceInternal(String name, String path) { 101 ResourceEntry entry = super.findResourceInternal(name, path); 102 if (entry != null && entry.binaryContent != null && path.endsWith(".class")) { 104 byte[] transformed = this.weavingTransformer.transformIfNecessary(name, entry.binaryContent); 105 entry.binaryContent = transformed; 106 } 107 return entry; 108 } 109 110 @Override 111 public String toString() { 112 StringBuilder sb = new StringBuilder (getClass().getName()); 113 sb.append("\r\n"); 114 sb.append(super.toString()); 115 return sb.toString(); 116 } 117 118 119 123 130 private static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException { 131 if (src == null) { 132 throw new IllegalArgumentException ("Source for field copy cannot be null"); 133 } 134 if (dest == null) { 135 throw new IllegalArgumentException ("Destination for field copy cannot be null"); 136 } 137 Class targetClass = findCommonAncestor(src.getClass(), dest.getClass()); 138 139 do { 141 Field [] fields = targetClass.getDeclaredFields(); 144 for (int i = 0; i < fields.length; i++) { 145 Field field = fields[i]; 146 if (!(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) || 149 field.getName().equals("resourceEntries"))) { 150 try { 151 field.setAccessible(true); 153 Object srcValue = field.get(src); 154 field.set(dest, srcValue); 155 } 156 catch (IllegalAccessException ex) { 157 throw new IllegalStateException ( 158 "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex); 159 } 160 } 161 } 162 targetClass = targetClass.getSuperclass(); 163 } 164 while (targetClass != null && targetClass != Object .class); 165 } 166 167 private static Class findCommonAncestor(Class one, Class two) throws IllegalArgumentException { 168 Class ancestor = one; 169 while (ancestor != Object .class || ancestor != null) { 170 if (ancestor.isAssignableFrom(two)) { 171 return ancestor; 172 } 173 ancestor = ancestor.getSuperclass(); 174 } 175 ancestor = two; 177 while (ancestor != Object .class || ancestor != null) { 178 if (ancestor.isAssignableFrom(one)) { 179 return ancestor; 180 } 181 ancestor = ancestor.getSuperclass(); 182 } 183 return null; 184 } 185 186 } 187 | Popular Tags |