1 29 30 package com.caucho.loader.enhancer; 31 32 import com.caucho.bytecode.ByteCodeClassMatcher; 33 import com.caucho.bytecode.ByteCodeClassScanner; 34 import com.caucho.bytecode.ByteCodeParser; 35 import com.caucho.bytecode.JClass; 36 import com.caucho.bytecode.JavaClass; 37 import com.caucho.bytecode.JavaClassLoader; 38 import com.caucho.java.WorkDir; 39 import com.caucho.java.gen.GenClass; 40 import com.caucho.java.gen.JavaClassGenerator; 41 import com.caucho.loader.DynamicClassLoader; 42 import com.caucho.loader.EnvironmentLocal; 43 import com.caucho.util.CharBuffer; 44 import com.caucho.util.L10N; 45 import com.caucho.util.Log; 46 import com.caucho.vfs.Path; 47 import com.caucho.vfs.ReadStream; 48 49 import java.io.ByteArrayInputStream ; 50 import java.lang.instrument.*; 51 import java.util.ArrayList ; 52 import java.security.*; 53 import java.util.logging.Level ; 54 import java.util.logging.Logger ; 55 56 59 public class EnhancerManager 60 implements ClassFileTransformer, ByteCodeClassMatcher 61 { 62 private static final L10N L = new L10N(EnhancerManager.class); 63 private static final Logger log = Log.open(EnhancerManager.class); 64 65 private static EnvironmentLocal<EnhancerManager> _localEnhancer = 66 new EnvironmentLocal<EnhancerManager>(); 67 68 private EnhancerManager _parent; 69 private DynamicClassLoader _loader; 70 71 private Path _workPath; 72 73 private JavaClassLoader _jClassLoader = new JavaClassLoader(); 74 private JavaClassGenerator _javaGen = new JavaClassGenerator(); 75 76 private ArrayList <ClassEnhancer> _classEnhancerList = 77 new ArrayList <ClassEnhancer>(); 78 79 private EnhancerManager(ClassLoader loader) 80 { 81 for (; 82 loader != null && ! (loader instanceof DynamicClassLoader); 83 loader = loader.getParent()) { 84 } 85 86 _loader = (DynamicClassLoader) loader; 87 88 if (loader != null) 89 _parent = getLocalEnhancer(loader.getParent()); 90 91 if (_parent != null) { 92 _classEnhancerList.addAll(_parent._classEnhancerList); 93 } 94 } 95 96 public static EnhancerManager create() 97 { 98 return create(Thread.currentThread().getContextClassLoader()); 99 } 100 101 public static EnhancerManager create(ClassLoader loader) 102 { 103 EnhancerManager enhancer = _localEnhancer.getLevel(loader); 104 105 if (enhancer == null) { 106 enhancer = new EnhancerManager(loader); 107 _localEnhancer.set(enhancer, loader); 108 109 for (; loader != null; loader = loader.getParent()) { 110 if (loader instanceof DynamicClassLoader) { 111 ((DynamicClassLoader) loader).addTransformer(enhancer); 112 break; 113 } 114 } 115 } 116 117 return enhancer; 118 } 119 120 public static EnhancerManager getLocalEnhancer(ClassLoader loader) 121 { 122 return _localEnhancer.get(loader); 123 } 124 125 128 public JavaClassLoader getJavaClassLoader() 129 { 130 return _jClassLoader; 131 } 132 133 136 public Path getWorkPath() 137 { 138 if (_workPath != null) 139 return _workPath; 140 else 141 return WorkDir.getLocalWorkDir(_loader); 142 } 143 144 147 public void setWorkPath(Path workPath) 148 { 149 _workPath = workPath; 150 } 151 152 155 public final Path getPreWorkPath() 156 { 157 return getWorkPath().lookup("pre-enhance"); 158 } 159 160 163 public final Path getPostWorkPath() 164 { 165 return getWorkPath().lookup("post-enhance"); 166 } 167 168 171 public void addClassEnhancer(ClassEnhancer classEnhancer) 172 { 173 _classEnhancerList.add(classEnhancer); 174 } 175 176 179 public void addClass(ClassEnhancerConfig config) 180 { 181 config.setEnhancerManager(this); 182 183 _classEnhancerList.add(config); 184 } 185 186 189 public byte[] transform(ClassLoader loader, 190 String className, 191 Class oldClass, 192 ProtectionDomain domain, 193 byte []buffer) 194 { 195 int length = buffer.length; 196 197 ByteCodeClassScanner scanner; 198 199 scanner = new ByteCodeClassScanner(className, buffer, 0, length, this); 201 202 if (scanner.scan()) { 203 try { 204 ByteCodeParser parser = new ByteCodeParser(); 205 parser.setClassLoader(_jClassLoader); 206 207 ByteArrayInputStream is; 208 is = new ByteArrayInputStream (buffer, 0, length); 209 210 JavaClass jClass = parser.parse(is); 211 212 return enhance(jClass); 213 } catch (Throwable e) { 214 throw new EnhancerRuntimeException(e); 215 } 216 } 217 218 return null; 219 } 220 221 224 public byte []enhance(JClass jClass) 225 throws ClassNotFoundException 226 { 227 String className = jClass.getName().replace('/', '.'); 228 String extClassName = className + "__ResinExt"; 229 230 try { 231 EnhancerPrepare prepare = new EnhancerPrepare(); 232 prepare.setWorkPath(getWorkPath()); 233 prepare.setClassLoader(_loader); 234 235 for (ClassEnhancer enhancer : _classEnhancerList) { 236 if (enhancer.shouldEnhance(className)) { 237 prepare.addEnhancer(enhancer); 238 } 239 } 240 241 prepare.renameClass(className, className); 243 } catch (Exception e) { 244 log.log(Level.FINE, e.toString(), e); 245 246 throw new ClassNotFoundException (e.toString()); 247 } 248 249 boolean hasEnhancer = false; 250 GenClass genClass = new GenClass(extClassName); 251 genClass.setSuperClassName(className); 252 253 for (ClassEnhancer enhancer : _classEnhancerList) { 254 if (enhancer.shouldEnhance(className)) { 255 try { 256 hasEnhancer = true; 257 enhancer.enhance(genClass, jClass, extClassName); 258 } catch (RuntimeException e) { 259 throw e; 260 } catch (Exception e) { 261 throw new RuntimeException (e); 262 } 263 } 264 } 265 267 try { 268 if (hasEnhancer) { 269 _javaGen.setWorkDir(getPreWorkPath()); 270 _javaGen.generate(genClass); 271 _javaGen.compilePendingJava(); 272 } 273 274 EnhancerFixup fixup = new EnhancerFixup(); 275 fixup.setJavaClassLoader(_jClassLoader); 276 fixup.setClassLoader(_loader); 277 fixup.setWorkPath(getWorkPath()); 278 279 for (ClassEnhancer enhancer : _classEnhancerList) { 280 if (enhancer.shouldEnhance(className)) { 281 fixup.addEnhancer(enhancer); 282 } 283 } 284 285 fixup.fixup(className, extClassName); 286 287 Path path = getPostWorkPath().lookup(className.replace('.', '/') + ".class"); 288 byte []buffer = new byte[(int) path.getLength()]; 289 290 ReadStream is = path.openRead(); 291 try { 292 is.readAll(buffer, 0, buffer.length); 293 } finally { 294 is.close(); 295 } 296 297 return buffer; 298 } catch (RuntimeException e) { 299 throw e; 300 } catch (Exception e) { 301 log.log(Level.FINE, e.toString(), e); 302 303 throw new ClassNotFoundException (e.getMessage()); 304 } 305 306 } 308 309 312 public boolean isClassMatch(String className) 313 { 314 if (className.lastIndexOf('$') >= 0) { 315 int p = className.lastIndexOf('$'); 316 char ch = className.charAt(p + 1); 317 318 if (ch >= '0' && ch <= '9') 319 return false; 320 } 321 else if (className.indexOf('+') > 0 || 322 className.indexOf('-') > 0) 323 return false; 324 325 for (int i = 0; i < _classEnhancerList.size(); i++) { 326 if (_classEnhancerList.get(i).shouldEnhance(className)) { 327 return true; 328 } 329 } 330 331 return false; 332 } 333 334 337 public boolean isMatch(CharBuffer cb) 338 { 339 return false; 340 } 341 } 342 | Popular Tags |