1 8 package org.codehaus.aspectwerkz.transform.aspectj; 9 10 import org.apache.bcel.classfile.JavaClass; 11 import org.apache.bcel.classfile.Method; 12 import org.apache.bcel.classfile.Attribute; 13 import org.apache.bcel.classfile.ClassParser; 14 import org.apache.bcel.classfile.Unknown; 15 import org.apache.bcel.generic.Type; 16 17 import java.util.*; 18 import java.io.InputStream ; 19 import java.io.IOException ; 20 import java.lang.reflect.Field ; 21 22 import org.aspectj.weaver.AjAttribute; 23 import org.aspectj.weaver.ISourceContext; 24 import org.aspectj.weaver.patterns.Pointcut; 25 import org.aspectj.weaver.patterns.KindedPointcut; 26 import org.aspectj.weaver.patterns.SignaturePattern; 27 28 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException; 29 import org.codehaus.aspectwerkz.exception.DefinitionException; 30 import org.codehaus.aspectwerkz.aspect.AdviceType; 31 import org.codehaus.aspectwerkz.definition.AspectDefinition; 32 import org.codehaus.aspectwerkz.definition.DefinitionParserHelper; 33 import org.codehaus.aspectwerkz.definition.AdviceDefinition; 34 import org.codehaus.aspectwerkz.reflect.ClassInfo; 35 import org.codehaus.aspectwerkz.reflect.MethodInfo; 36 import org.codehaus.aspectwerkz.transform.inlining.spi.AspectModel; 37 import org.codehaus.aspectwerkz.transform.inlining.AdviceMethodInfo; 38 import org.codehaus.aspectwerkz.transform.inlining.AspectInfo; 39 import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler; 40 import org.codehaus.aspectwerkz.transform.TransformationConstants; 41 42 import org.codehaus.aspectwerkz.org.objectweb.asm.ClassWriter; 43 import org.codehaus.aspectwerkz.org.objectweb.asm.CodeVisitor; 44 45 53 public class AspectJAspectModel implements AspectModel, TransformationConstants { 54 55 private static final String ASPECT_MODEL_TYPE = "aspectj"; 56 private static final String ASPECTJ_AROUND_CLOSURE_CLASS_NAME = "org/aspectj/runtime/internal/AroundClosure"; 57 private static final String ASPECTJ_AROUND_CLOSURE_RUN_METHOD_NAME = "run"; 58 private static final String ASPECTJ_AROUND_CLOSURE_RUN_METHOD_SIGNATURE = "([Ljava/lang/Object;)Ljava/lang/Object;"; 59 private static final String PREFIX_AROUND_ADVICE = "ajc$around$"; 60 private static final String PREFIX_BEFORE_ADVICE = "ajc$before$"; 61 private static final String PREFIX_AFTER_FINALLY_ADVICE = "ajc$after$"; 62 private static final String PREFIX_AFTER_THROWING_ADVICE = "ajc$afterThrowing$"; 63 private static final String PREFIX_AFTER_RETURNING_ADVICE = "ajc$afterReturning$"; 64 private static final String PROCEED_SUFFIX = "proceed"; 65 66 72 public String getAspectModelType() { 73 return ASPECT_MODEL_TYPE; 74 } 75 76 83 public void defineAspect(final ClassInfo classInfo, 84 final AspectDefinition aspectDef, 85 final ClassLoader loader) { 86 87 JavaClass javaClass = null; 88 String classFileName = classInfo.getName().replace('.', '/') + ".class"; 89 try { 90 InputStream classStream = loader.getResourceAsStream(classFileName); 91 ClassParser classParser = new ClassParser(classStream, classFileName); 92 javaClass = classParser.parse(); 93 } catch (IOException e) { 94 throw new WrappedRuntimeException(e); 95 } 96 97 List attributes = getAspectAttributes(javaClass); 98 if (attributes.size() == 0) { 99 return; } 101 102 aspectDef.setAspectModel(getAspectModelType()); 103 104 for (Iterator it = attributes.iterator(); it.hasNext();) { 105 AjAttribute attr = (AjAttribute) it.next(); 106 if (attr instanceof AjAttribute.PointcutDeclarationAttribute) { 107 AjAttribute.PointcutDeclarationAttribute pcAttr = (AjAttribute.PointcutDeclarationAttribute) attr; 108 Pointcut pointcut = pcAttr.reify().getPointcut(); 109 if (pointcut instanceof KindedPointcut) { 110 try { 111 Field sigField = KindedPointcut.class.getDeclaredField("signature"); 112 sigField.setAccessible(true); 113 SignaturePattern signature = (SignaturePattern) sigField.get(pointcut); 114 DefinitionParserHelper.createAndAddPointcutDefToAspectDef( 115 signature.getName().toString(), pointcut.toString(), aspectDef 116 ); 117 } catch (Exception e) { 118 throw new WrappedRuntimeException(e); 119 } 120 } 121 } 122 } 123 for (Iterator iterator = getAroundAdviceInfo(javaClass).iterator(); iterator.hasNext();) { 124 AdviceInfo ajAdviceInfo = (AdviceInfo) iterator.next(); 125 AdviceDefinition adviceDef = handleAdviceInfo(classInfo, aspectDef, ajAdviceInfo); 126 aspectDef.addAroundAdviceDefinition(adviceDef); 127 } 128 for (Iterator iterator = getBeforeAdviceInfo(javaClass).iterator(); iterator.hasNext();) { 129 AdviceInfo ajAdviceInfo = (AdviceInfo) iterator.next(); 130 AdviceDefinition adviceDef = handleAdviceInfo(classInfo, aspectDef, ajAdviceInfo); 131 aspectDef.addBeforeAdviceDefinition(adviceDef); 132 } 133 for (Iterator iterator = getAfterFinallyAdviceInfo(javaClass).iterator(); iterator.hasNext();) { 134 AdviceInfo ajAdviceInfo = (AdviceInfo) iterator.next(); 135 AdviceDefinition adviceDef = handleAdviceInfo(classInfo, aspectDef, ajAdviceInfo); 136 aspectDef.addAfterAdviceDefinition(adviceDef); 137 } 138 for (Iterator iterator = getAfterReturningAdviceInfo(javaClass).iterator(); iterator.hasNext();) { 139 AdviceInfo ajAdviceInfo = (AdviceInfo) iterator.next(); 140 AdviceDefinition adviceDef = handleAdviceInfo(classInfo, aspectDef, ajAdviceInfo); 141 aspectDef.addAfterAdviceDefinition(adviceDef); 142 } 143 for (Iterator iterator = getAfterThrowingAdviceInfo(javaClass).iterator(); iterator.hasNext();) { 144 AdviceInfo ajAdviceInfo = (AdviceInfo) iterator.next(); 145 AdviceDefinition adviceDef = handleAdviceInfo(classInfo, aspectDef, ajAdviceInfo); 146 aspectDef.addAfterAdviceDefinition(adviceDef); 147 } 148 } 149 150 156 public boolean requiresReflectiveInfo() { 157 return false; 158 } 159 160 165 public AroundClosureClassInfo getAroundClosureClassInfo() { 166 return new AspectModel.AroundClosureClassInfo( ASPECTJ_AROUND_CLOSURE_CLASS_NAME, new String []{}); 167 } 168 169 170 176 public void createMandatoryMethods(final ClassWriter cw, final String className) { 177 CodeVisitor cv = cw.visitMethod( 178 ACC_PUBLIC, ASPECTJ_AROUND_CLOSURE_RUN_METHOD_NAME, 179 ASPECTJ_AROUND_CLOSURE_RUN_METHOD_SIGNATURE, 180 new String []{THROWABLE_CLASS_NAME}, 181 null 182 ); 183 cv.visitVarInsn(ALOAD, 0); 184 cv.visitMethodInsn(INVOKEVIRTUAL, className, PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE); 185 cv.visitInsn(ARETURN); 186 cv.visitMaxs(0, 0); 187 } 188 189 194 public void createInvocationOfAroundClosureSuperClass(final CodeVisitor cv) { 195 cv.visitInsn(ACONST_NULL); 196 cv.visitMethodInsn( 197 INVOKESPECIAL, 198 ASPECTJ_AROUND_CLOSURE_CLASS_NAME, 199 INIT_METHOD_NAME, 200 "([Ljava/lang/Object;)V" 201 ); 202 } 203 204 213 public void createAspectReferenceField(final ClassWriter cw, 214 final AspectInfo aspectInfo, 215 final String joinPointClassName) { 216 AbstractJoinPointCompiler.createAspectReferenceField(cw, aspectInfo); 217 } 218 219 228 public void createAspectInstantiation(final CodeVisitor cv, 229 final AspectInfo aspectInfo, 230 final String joinPointClassName) { 231 cv.visitMethodInsn( 232 INVOKESTATIC, 233 aspectInfo.getAspectClassName(), 234 "aspectOf()", 235 "()" + aspectInfo.getAspectClassSignature() 236 ); 237 cv.visitFieldInsn( 239 PUTSTATIC, joinPointClassName, aspectInfo.getAspectFieldName(), aspectInfo.getAspectClassSignature() 240 ); 241 242 } 243 244 250 public void createAroundAdviceArgumentHandling(final CodeVisitor cv, final AdviceMethodInfo adviceMethodInfo) { 251 } 252 253 259 public void createBeforeAdviceArgumentHandling(final CodeVisitor cv, final AdviceMethodInfo adviceMethodInfo) { 260 } 261 262 268 public void createAfterAdviceArgumentHandling(final CodeVisitor cv, final AdviceMethodInfo adviceMethodInfo) { 269 final AdviceType adviceType = adviceMethodInfo.getAdviceInfo().getType(); 270 final int specialArgumentIndex = adviceMethodInfo.getSpecialArgumentIndex(); 271 final String specialArgumentTypeName = adviceMethodInfo.getSpecialArgumentTypeName(); 272 if (adviceType.equals(AdviceType.AFTER_RETURNING) || 273 adviceType.equals(AdviceType.AFTER_THROWING)) { 274 cv.visitVarInsn(ALOAD, specialArgumentIndex); 275 cv.visitTypeInsn(CHECKCAST, specialArgumentTypeName); 276 } 277 } 278 279 287 private AdviceDefinition handleAdviceInfo(final ClassInfo classInfo, 288 final AspectDefinition aspectDef, 289 final AdviceInfo ajAdviceInfo) { 290 291 MethodInfo adviceMethod = null; 292 MethodInfo[] methods = classInfo.getMethods(); 293 for (int i = 0; i < methods.length; i++) { 294 MethodInfo method = methods[i]; 295 if (method.getName().equals(ajAdviceInfo.adviceMethodName)) { 296 adviceMethod = method; 297 break; 298 } 299 } 300 if (adviceMethod == null) { 301 throw new Error ( 302 "advice method [" + ajAdviceInfo.adviceMethodName + 303 "] could not be found in class [" + classInfo.getName() + "]" 304 ); 305 } 306 String specialArgType = null; 307 if (ajAdviceInfo.extraParameterFlags != 0) { 308 specialArgType = ajAdviceInfo.parameterTypes[0]; 309 } 310 return AdviceDefinition.newInstance( 311 createFullAspectJAdviceMethodName(ajAdviceInfo), 312 ajAdviceInfo.type, 313 ajAdviceInfo.pointcut, 314 specialArgType, 315 classInfo.getName(), 316 classInfo.getName(), 317 adviceMethod, 318 aspectDef 319 ); 320 } 321 322 328 private String createFullAspectJAdviceMethodName(final AdviceInfo ajAdviceInfo) { 329 StringBuffer fullAdviceMethodName = new StringBuffer (); 330 fullAdviceMethodName.append(ajAdviceInfo.adviceMethodName).append('('); 331 332 fullAdviceMethodName.append(')'); 341 return fullAdviceMethodName.toString(); 342 } 343 344 350 private List getAroundAdviceInfo(final JavaClass javaClass) { 351 List advice = new ArrayList(); 352 Method[] methods = javaClass.getMethods(); 353 for (int i = 0; i < methods.length; i++) { 354 Method method = methods[i]; 355 String adviceName = method.getName(); 356 if (adviceName.startsWith(PREFIX_AROUND_ADVICE) && !adviceName.endsWith(PROCEED_SUFFIX)) { 357 advice.add(createAdviceInfo(javaClass, AdviceType.AROUND, method)); 358 } 359 } 360 return advice; 361 } 362 363 369 private List getBeforeAdviceInfo(final JavaClass javaClass) { 370 List advice = new ArrayList(); 371 Method[] methods = javaClass.getMethods(); 372 for (int i = 0; i < methods.length; i++) { 373 Method method = methods[i]; 374 String adviceName = method.getName(); 375 if (adviceName.startsWith(PREFIX_BEFORE_ADVICE)) { 376 advice.add(createAdviceInfo(javaClass, AdviceType.BEFORE, method)); 377 } 378 } 379 return advice; 380 } 381 382 388 private List getAfterFinallyAdviceInfo(final JavaClass javaClass) { 389 List advice = new ArrayList(); 390 Method[] methods = javaClass.getMethods(); 391 for (int i = 0; i < methods.length; i++) { 392 Method method = methods[i]; 393 String adviceName = method.getName(); 394 if (adviceName.startsWith(PREFIX_AFTER_FINALLY_ADVICE)) { 395 advice.add(createAdviceInfo(javaClass, AdviceType.AFTER_FINALLY, method)); 396 } 397 } 398 return advice; 399 } 400 401 407 private List getAfterThrowingAdviceInfo(final JavaClass javaClass) { 408 List advice = new ArrayList(); 409 Method[] methods = javaClass.getMethods(); 410 for (int i = 0; i < methods.length; i++) { 411 Method method = methods[i]; 412 String adviceName = method.getName(); 413 if (adviceName.startsWith(PREFIX_AFTER_THROWING_ADVICE)) { 414 advice.add(createAdviceInfo(javaClass, AdviceType.AFTER_THROWING, method)); 415 } 416 } 417 return advice; 418 } 419 420 426 private List getAfterReturningAdviceInfo(final JavaClass javaClass) { 427 List advice = new ArrayList(); 428 Method[] methods = javaClass.getMethods(); 429 for (int i = 0; i < methods.length; i++) { 430 Method method = methods[i]; 431 String adviceName = method.getName(); 432 if (adviceName.startsWith(PREFIX_AFTER_RETURNING_ADVICE)) { 433 advice.add(createAdviceInfo(javaClass, AdviceType.AFTER_RETURNING, method)); 434 } 435 } 436 return advice; 437 } 438 439 446 private AdviceInfo createAdviceInfo(final JavaClass javaClassfinal, 447 final AdviceType adviceType, 448 final Method method) { 449 Attribute[] attributes = method.getAttributes(); 450 List ajAttributes = readAjAttributes(attributes, null); 451 AdviceInfo adviceInfo = new AdviceInfo(); 452 for (Iterator it = ajAttributes.iterator(); it.hasNext();) { 453 AjAttribute attr = (AjAttribute) it.next(); 454 if (attr instanceof AjAttribute.AdviceAttribute) { 455 AjAttribute.AdviceAttribute adviceAttr = (AjAttribute.AdviceAttribute) attr; 456 adviceInfo.type = adviceType; 457 adviceInfo.aspectClassName = javaClassfinal.getClassName().replace('.', '/'); 458 adviceInfo.adviceMethodName = method.getName(); 459 String pointcut = adviceAttr.getPointcut().toString(); 460 if (pointcut.startsWith("execution(") || 461 pointcut.startsWith("call(") || 462 pointcut.startsWith("set(") || 463 pointcut.startsWith("get(") || 464 pointcut.startsWith("handler(") || 465 pointcut.startsWith("adviceexecution(") || 466 pointcut.startsWith("within(") || 467 pointcut.startsWith("withincode(") || 468 pointcut.startsWith("cflow(") || 469 pointcut.startsWith("cflowbelow(") || 470 pointcut.startsWith("if(") || 471 pointcut.startsWith("this(") || 472 pointcut.startsWith("target(") || 473 pointcut.startsWith("args(") || 474 pointcut.startsWith("initialization(") || 475 pointcut.startsWith("staticinitialization(") || 476 pointcut.startsWith("preinitialization(")) { 477 adviceInfo.pointcut = pointcut; 478 } else if (pointcut.endsWith("()")) { 479 adviceInfo.pointcut = pointcut.substring(0, pointcut.length() - 2); 480 } else { 481 throw new DefinitionException("pointcuts of type [" + pointcut + " are not yet supported"); 482 } 483 adviceInfo.extraParameterFlags = adviceAttr.getExtraParameterFlags(); 484 int nrArgs = method.getArgumentTypes().length; 485 String [] parameterTypes = new String [nrArgs]; 486 for (int i = 0; i < nrArgs; i++) { 487 Type type = method.getArgumentTypes()[i]; 488 parameterTypes[i] = type.toString().replace('.', '/'); 489 } 490 adviceInfo.parameterTypes = parameterTypes; 491 } 492 } 493 return adviceInfo; 494 } 495 496 502 private List getAspectAttributes(final JavaClass javaClass) { 503 return readAjAttributes(javaClass.getAttributes(), null); 504 } 505 506 513 private static List readAjAttributes(final Attribute[] attrs, final ISourceContext context) { 514 List ajAttrs = new ArrayList(); 515 for (int i = attrs.length - 1; i >= 0; i--) { 516 Attribute a = attrs[i]; 517 if (a instanceof Unknown) { 518 Unknown u = (Unknown) a; 519 String name = u.getName(); 520 if (name.startsWith(AjAttribute.AttributePrefix)) { 521 ajAttrs.add(AjAttribute.read(name, u.getBytes(), context)); 522 } 523 } 524 } 525 return ajAttrs; 526 } 527 } 528 | Popular Tags |