1 22 package org.jboss.aop.instrument; 23 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import org.jboss.aop.AspectManager; 28 import org.jboss.aop.ClassAdvisor; 29 import org.jboss.aop.pointcut.Pointcut; 30 import org.jboss.aop.util.Advisable; 31 import org.jboss.aop.util.JavassistMethodHashing; 32 import javassist.CannotCompileException; 33 import javassist.CtBehavior; 34 import javassist.CtClass; 35 import javassist.CtConstructor; 36 import javassist.CtMethod; 37 import javassist.Modifier; 38 import javassist.NotFoundException; 39 import javassist.expr.ExprEditor; 40 import javassist.expr.MethodCall; 41 import javassist.expr.NewExpr; 42 43 48 49 public abstract class CallerTransformer 50 { 51 public static final String CON_BY_CON_INFO_CLASS_NAME = org.jboss.aop.ConByConInfo.class.getName(); 52 public static final String CON_BY_METHOD_INFO_CLASS_NAME = org.jboss.aop.ConByMethodInfo.class.getName(); 53 public static final String METHOD_BY_CON_INFO_CLASS_NAME = org.jboss.aop.MethodByConInfo.class.getName(); 54 public static final String METHOD_BY_METHOD_INFO_CLASS_NAME = org.jboss.aop.MethodByMethodInfo.class.getName(); 55 56 Instrumentor instrumentor; 57 boolean optimize; 58 AspectManager manager; 59 CallerInfoAdder callerInfoAdder; 60 61 63 protected CallerTransformer( 65 Instrumentor instrumentor, 66 AspectManager manager, 67 boolean optimize, 68 CallerInfoAdder callerInfoAdder) 69 { 70 this.instrumentor = instrumentor; 71 this.optimize = optimize; 72 this.manager = manager; 73 this.callerInfoAdder = callerInfoAdder; 74 } 75 76 protected abstract CallerExprEditor callerExprEditorFactory(ClassAdvisor advisor, CtClass clazz); 77 78 public boolean applyCallerPointcuts(CtClass clazz, ClassAdvisor advisor) throws CannotCompileException 79 { 80 if (!advisor.getManager().isWithin() && !advisor.getManager().isCall() && !advisor.getManager().isWithincode()) 81 { 82 if (AspectManager.verbose) System.out.println("[debug] There are no caller pointcuts!"); 83 return false; 84 } 85 CallerExprEditor expr = callerExprEditorFactory(advisor, clazz); 86 CtMethod[] methods = clazz.getDeclaredMethods(); 87 for (int i = 0; i < methods.length; i++) 88 { 89 if (Advisable.isAdvisable(methods[i])) 90 { 91 methods[i].instrument(expr); 92 } 93 } 94 95 CtConstructor[] cons = clazz.getDeclaredConstructors(); 96 for (int i = 0; i < cons.length; i++) 97 { 98 cons[i].instrument(expr); 99 } 100 101 return expr.appliedCallerBinding; 102 } 103 104 private boolean isTargetConstructorAdvised(CtConstructor calledConstructor) 105 { 106 try 107 { 108 ClassAdvisor adv = manager.getTempClassAdvisor(calledConstructor.getDeclaringClass()); 109 return ConstructorExecutionTransformer.isAdvisableConstructor(calledConstructor, adv); 110 } 111 catch (Exception e) 112 { 113 throw new RuntimeException (e); 114 } 115 } 116 117 118 private static String getHashString(long hash) 119 { 120 if (hash < 0) 121 { 122 return "_N_" + (-1 * hash); 123 } 124 else 125 { 126 return "_" + hash; 127 } 128 } 129 130 protected static String getUniqueInvocationFieldname(long callingHash, String classname, long calledHash) 131 { 132 classname = classname.replace('.', '_'); 133 classname = classname.replace('/', '_'); 134 135 return getHashString(callingHash) + classname + getHashString(calledHash); 136 } 137 138 protected static String getConByConInfoName(long callingIndex, String classname, long calledHash) 139 { 140 return "aop$constructorCall_con_" + getUniqueInvocationFieldname(callingIndex, classname, calledHash); 141 } 142 143 protected static String getConByMethodInfoName(long callingHash, String classname, long calledHash) 144 { 145 return "aop$constructorCall_" + getUniqueInvocationFieldname(callingHash, classname, calledHash); 146 } 147 148 protected static String getMethodByConInfoName(int index, String classname, long calledHash) 149 { 150 return "aop$methodCall_con_" + getUniqueInvocationFieldname(index, classname, calledHash); 151 } 152 153 protected static String getMethodByMethodInfoName(long callingHash, String classname, long calledHash) 154 { 155 return "aop$methodCall_" + getUniqueInvocationFieldname(callingHash, classname, calledHash); 156 } 157 158 protected static String conByConInfoFromWeakReference(String localName, String infoName) 159 { 160 return TransformerCommon.infoFromWeakReference(CON_BY_CON_INFO_CLASS_NAME, localName, infoName); 161 } 162 163 protected static String conByMethodInfoFromWeakReference(String localName, String infoName) 164 { 165 return TransformerCommon.infoFromWeakReference(CON_BY_METHOD_INFO_CLASS_NAME, localName, infoName); 166 } 167 168 protected static String methodByMethodInfoFromWeakReference(String localName, String infoName) 169 { 170 return TransformerCommon.infoFromWeakReference(METHOD_BY_METHOD_INFO_CLASS_NAME, localName, infoName); 171 } 172 173 protected static String methodByConInfoFromWeakReference(String localName, String infoName) 174 { 175 return TransformerCommon.infoFromWeakReference(METHOD_BY_CON_INFO_CLASS_NAME, localName, infoName); 176 } 177 178 179 protected class ConstructorDetail 180 { 181 MethodCall call; 182 CtConstructor con; 183 int callingIndex; 184 long calledHash; 185 String callerInfoField; 186 CtMethod calledMethod; 187 String classname; 188 189 ConstructorDetail(CallerExprEditor editor, MethodCall call, String classname)throws NotFoundException 190 { 191 this.call = call; 192 con = (CtConstructor) call.where(); 193 callingIndex = editor.constructors.indexOf(con); 194 calledHash = JavassistMethodHashing.methodHash(call.getMethod()); 195 callerInfoField = getMethodByConInfoName(callingIndex, classname, calledHash); 196 calledMethod = call.getMethod(); 197 this.classname = classname; 198 } 199 } 200 201 protected class MethodDetail 202 { 203 MethodCall call; 204 CtMethod where; 205 long callingHash; 206 long calledHash; 207 String callerInfoField; 208 CtMethod calledMethod; 209 String classname; 210 211 MethodDetail(CallerExprEditor editor, MethodCall call, String classname) throws NotFoundException 212 { 213 this.call = call; 214 where = (CtMethod) call.where(); 215 callingHash = JavassistMethodHashing.methodHash((where)); 216 calledHash = JavassistMethodHashing.methodHash(call.getMethod()); 217 callerInfoField = getMethodByMethodInfoName(callingHash, classname, calledHash); 218 calledMethod = call.getMethod(); 219 220 this.classname = classname; 221 } 222 } 223 224 protected class ConByMethodDetail 225 { 226 NewExpr call; 227 boolean isTgtConAdvised; 228 CtMethod where; 229 long callingHash; 230 long calledHash; 231 String callerInfoField; 232 CtConstructor calledConstructor; 233 String classname; 234 235 ConByMethodDetail(CallerExprEditor editor, NewExpr call, String classname)throws NotFoundException 236 { 237 this.call = call; 238 where = (CtMethod) call.where(); 239 callingHash = JavassistMethodHashing.methodHash(where); 240 calledHash = JavassistMethodHashing.constructorHash(call.getConstructor()); 241 callerInfoField = getConByMethodInfoName(callingHash, classname, calledHash); 242 calledConstructor = call.getConstructor(); 243 this.classname = classname; 244 isTgtConAdvised = isTargetConstructorAdvised(calledConstructor); 245 } 246 } 247 248 protected class ConByConDetail 249 { 250 NewExpr call; 251 boolean isTgtConAdvised; 252 CtConstructor con; 253 int callingIndex; 254 long calledHash; 255 String callerInfoField; 256 CtConstructor calledConstructor; 257 String classname; 258 259 ConByConDetail(CallerExprEditor editor, NewExpr call, String classname)throws NotFoundException 260 { 261 this.call = call; 262 con = (CtConstructor) call.where(); 263 callingIndex = editor.constructors.indexOf(con); 264 calledHash = JavassistMethodHashing.constructorHash(call.getConstructor()); 265 callerInfoField = getConByConInfoName(callingIndex, classname, calledHash); 266 calledConstructor = call.getConstructor(); 267 this.classname = classname; 268 isTgtConAdvised = isTargetConstructorAdvised(calledConstructor); 269 } 270 } 271 272 abstract class CallerExprEditor extends ExprEditor 273 { 274 CtClass callingClass; 275 ClassAdvisor advisor; 276 List constructors; 277 public boolean appliedCallerBinding = false; 278 279 HashMap callerInfos = new HashMap (); 280 int invocationCounter = 0; 281 282 public CallerExprEditor(ClassAdvisor advisor, CtClass callingClass) 283 { 284 this.advisor = advisor; 285 this.callingClass = callingClass; 286 this.constructors = instrumentor.getConstructors(callingClass); 287 } 288 289 private String getUniqueInvocationClassname(String classname) 290 { 291 return classname + "_" + (++invocationCounter) + "_"; 292 } 293 294 protected String getOptimizedConCalledByMethodInvocationClassName(long callingHash, String classname, long calledHash) 295 { 296 return getUniqueInvocationClassname(classname) + "ConByMInvocation"; 297 } 298 299 protected String getOptimizedConCalledByConInvocationClassName(long callingIndex, String classname, long calledHash) 300 { 301 return getUniqueInvocationClassname(classname) + "ConByConInvocation"; 302 } 303 304 protected String getOptimizedMethodCalledByMethodClassName(long callingHash, String classname, long calledHash) 305 { 306 return getUniqueInvocationClassname(classname) + "MByMInvocation"; 307 } 308 309 protected String getOptimizedMethodCalledByConstructorClassName(int callingIndex, String classname, long calledHash) 310 { 311 return getUniqueInvocationClassname(classname) + "MByConInvocation"; 312 } 313 314 public void edit(MethodCall call) throws CannotCompileException 315 { 316 try 317 { 318 320 String classname = call.getClassName(); 321 String methodName = call.getMethodName(); 322 if (ClassAdvisor.isWithoutAdvisement(methodName) 323 || methodName.startsWith("_") 324 || classname.startsWith("org.jboss.aop") 325 || call.getMethodName().equals("class$") || !Instrumentor.isTransformable(callingClass) 327 ) 328 { 329 return; 331 } 332 333 CtBehavior behavior = call.where(); 334 335 boolean hasPointcut = false; 336 337 DeclareChecker.checkDeclares(manager, call, advisor); 338 339 Iterator it = manager.getPointcuts().values().iterator(); 341 while (it.hasNext()) 342 { 343 Pointcut p = (Pointcut) it.next(); 344 if (p.matchesCall(advisor, call)) 345 { 346 hasPointcut = true; 347 break; 348 } 349 else 350 { 351 if (AspectManager.verbose) System.out.println("[debug] MethodCall does not match: " + p.getExpr()); 352 } 353 } 354 if (hasPointcut) 355 { 356 if (behavior instanceof CtMethod) 357 modifyMethod(call, classname); 358 else if (behavior instanceof CtConstructor) modifyConstructor(call, classname); 359 } 360 } 361 catch (Exception ex) 362 { 363 System.err.println("error getting:" + call.getClassName() + ". '" + call.getMethodName() + "'"); 364 ex.printStackTrace(); 365 throw new CannotCompileException(ex); 366 } 367 } 368 369 370 private void modifyConstructor(MethodCall call, String classname) throws NotFoundException, CannotCompileException 371 { 372 instrumentor.setupBasics(callingClass); 373 ConstructorDetail cd = new ConstructorDetail(this, call, classname); 374 setupConstructor(cd); 375 replaceMethodCallInCon(cd); 376 appliedCallerBinding = true; 377 } 378 379 381 protected void replaceMethodCallInCon(ConstructorDetail cd)throws CannotCompileException, NotFoundException 382 { 383 String replaced = 384 methodByConInfoFromWeakReference("info", cd.callerInfoField) + 385 "if (info.getInterceptors() != (org.jboss.aop.advice.Interceptor[])null) { " + 386 "$_ = ($r)aop$classAdvisor$aop.invokeConstructorCaller(info, $0, $args);" + 387 "} else { " + 389 "$_ = $proceed($$); " + 390 "}"; 391 cd.call.replace(replaced); 392 } 393 394 private void modifyMethod(MethodCall call, String classname) throws NotFoundException, CannotCompileException 395 { 396 instrumentor.setupBasics(callingClass); 397 MethodDetail md = new MethodDetail(this, call, classname); 398 setupMethod(md); 399 replaceMethodCallInMethod(md); 400 appliedCallerBinding = true; 401 } 402 403 405 protected void replaceMethodCallInMethod(MethodDetail md)throws NotFoundException, CannotCompileException 406 { 407 String callingObject = ", null"; 408 if (!Modifier.isStatic(md.where.getModifiers())) 409 { 410 callingObject = ", this"; 411 } 412 String replaced = 413 methodByMethodInfoFromWeakReference("info", md.callerInfoField) + 414 "if (info.getInterceptors() != (org.jboss.aop.advice.Interceptor[])null) { " + 415 "$_ = ($r)aop$classAdvisor$aop.invokeCaller(info" + callingObject + ", $0, $args);" + 416 "} else { " + 418 "$_ = $proceed($$); " + 419 "}"; 420 md.call.replace(replaced); 421 } 422 423 424 public void edit(NewExpr call) throws CannotCompileException 425 { 426 try 427 { 428 String classname = call.getClassName(); 429 if (classname.startsWith("org.jboss.aop") || !Instrumentor.isTransformable(callingClass)) 430 { 431 return; 432 } 433 434 DeclareChecker.checkDeclares(manager, call, advisor); 435 436 boolean hasPointcut = false; 437 438 Iterator it = manager.getPointcuts().values().iterator(); 440 while (it.hasNext()) 441 { 442 Pointcut p = (Pointcut) it.next(); 443 if (p.matchesCall(advisor, call)) 444 { 445 hasPointcut = true; 446 break; 447 } 448 } 449 if (hasPointcut) 450 { 451 CtBehavior behavior = call.where(); 452 if (behavior instanceof CtMethod) 453 modifyMethod(call, classname); 454 else if (behavior instanceof CtConstructor) modifyConstructor(call, classname); 455 } 456 } 457 catch (Exception ex) 458 { 459 System.out.println(ex.getMessage()); 460 ex.printStackTrace(); 461 throw new CannotCompileException(ex); 462 } 463 } 464 465 private void modifyMethod(NewExpr call, String classname) throws Exception , NotFoundException, CannotCompileException 466 { 467 instrumentor.setupBasics(callingClass); 468 ConByMethodDetail cd = new ConByMethodDetail(this, call, classname); 469 setupMethod(cd); 470 replaceConCallInMethod(cd); 471 appliedCallerBinding = true; 472 } 473 474 476 protected void replaceConCallInMethod(ConByMethodDetail cd) throws NotFoundException, CannotCompileException 477 { 478 String callingObject = "null"; 479 if (!Modifier.isStatic(cd.where.getModifiers())) 480 { 481 callingObject = "this"; 482 } 483 484 String replaced = 485 conByMethodInfoFromWeakReference("info", cd.callerInfoField) + 486 "if (info.getInterceptors() != (org.jboss.aop.advice.Interceptor[])null) { " + 487 "java.lang.Object callingObject = " + callingObject + "; " + 488 "$_ = ($r)aop$classAdvisor$aop.invokeConCalledByMethod(info, " + callingObject + ", $args);" + 489 "} else { " + 491 "$_ = $proceed($$); " + 492 "}"; 493 494 cd.call.replace(replaced); 495 } 496 497 private void modifyConstructor(NewExpr call, String classname) throws Exception , NotFoundException, CannotCompileException 498 { 499 instrumentor.setupBasics(callingClass); 500 ConByConDetail cd = new ConByConDetail(this, call, classname); 501 setupConstructor(cd); 502 replaceConCallInCon(cd); 503 appliedCallerBinding = true; 504 } 505 506 508 protected void replaceConCallInCon(ConByConDetail cd)throws CannotCompileException, NotFoundException 509 { 510 String replaced = 511 conByConInfoFromWeakReference("info", cd.callerInfoField) + 512 "if (info.getInterceptors() != (org.jboss.aop.advice.Interceptor[])null) { " + 513 "$_ = ($r)aop$classAdvisor$aop.invokeConCalledByCon(info, $args);" + 514 "} else { " + 516 "$_ = $proceed($$); " + 517 "}"; 518 519 cd.call.replace(replaced); 520 } 521 522 protected abstract void setupConstructor(ConstructorDetail cd)throws NotFoundException, CannotCompileException; 523 protected abstract void setupMethod(MethodDetail md) throws NotFoundException, CannotCompileException; 524 protected abstract void setupMethod(ConByMethodDetail cd) throws NotFoundException, CannotCompileException; 525 protected abstract void setupConstructor(ConByConDetail cd)throws NotFoundException, CannotCompileException; 526 527 } 528 } 529 | Popular Tags |