1 22 package org.jboss.aop.instrument; 23 24 import java.lang.reflect.Method ; 25 26 import javassist.CannotCompileException; 27 import javassist.CtClass; 28 import javassist.CtConstructor; 29 import javassist.CtField; 30 import javassist.CtMethod; 31 import javassist.CtNewConstructor; 32 import javassist.CtNewMethod; 33 import javassist.Modifier; 34 import javassist.NotFoundException; 35 36 import org.jboss.aop.GeneratedClassAdvisor; 37 import org.jboss.aop.JoinPointInfo; 38 import org.jboss.aop.MethodByMethodInfo; 39 import org.jboss.aop.advice.AdviceMethodProperties; 40 import org.jboss.aop.joinpoint.MethodCalledByMethodInvocation; 41 import org.jboss.aop.util.ReflectToJavassist; 42 43 public class MethodByMethodJoinPointGenerator extends JoinPointGenerator 44 { 45 public static final String GENERATOR_PREFIX = JoinPointGenerator.GENERATOR_PREFIX + "MByM_"; 46 public static final String JOINPOINT_CLASS_PREFIX = JoinPointGenerator.JOINPOINT_CLASS_PREFIX + "MByM_"; 47 public static final String JOINPOINT_FIELD_PREFIX = JoinPointGenerator.JOINPOINT_FIELD_PREFIX + "MByM_"; 48 private static final Class INVOCATION_TYPE = MethodCalledByMethodInvocation.class; 49 private static final CtClass INVOCATION_CT_TYPE; 50 static 51 { 52 try 53 { 54 INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(INVOCATION_TYPE); 55 } 56 catch (NotFoundException e) 57 { 58 throw new RuntimeException (e); 59 } 60 } 61 62 public MethodByMethodJoinPointGenerator(GeneratedClassAdvisor advisor, JoinPointInfo info) 63 { 64 super(advisor, info); 65 } 66 67 protected void initialiseJoinPointNames() 68 { 69 joinpointClassName = getInfoClassName( 70 callingMethodHash(), 71 calledClass(), 72 calledMethodHash()); 73 74 joinpointFieldName = getInfoFieldName( 75 callingMethodHash(), 76 calledClass(), 77 calledMethodHash()); 78 } 79 80 private long callingMethodHash() 81 { 82 return ((MethodByMethodInfo)info).getCallingMethodHash(); 83 } 84 85 private String calledClass() 86 { 87 return ((MethodByMethodInfo)info).getCalledClass().getName(); 88 } 89 90 private long calledMethodHash() 91 { 92 return ((MethodByMethodInfo)info).getCalledMethodHash(); 93 } 94 95 protected boolean isVoid() 96 { 97 return ((MethodByMethodInfo)info).getMethod().getReturnType().equals(Void.TYPE); 98 } 99 100 protected Class getReturnType() 101 { 102 if (isVoid()) return null; 103 return ((MethodByMethodInfo)info).getMethod().getReturnType(); 104 } 105 106 protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup) 107 { 108 Method method = ((MethodByMethodInfo)info).getMethod(); 109 return new AdviceMethodProperties( 110 setup.getAspectClass(), 111 setup.getAdviceName(), 112 info.getClass(), 113 INVOCATION_TYPE, 114 method.getReturnType(), 115 method.getParameterTypes(), 116 method.getExceptionTypes()); 117 } 118 119 protected boolean isCaller() 120 { 121 return true; 122 } 123 124 protected boolean hasCallingObject() 125 { 126 return !java.lang.reflect.Modifier.isStatic(((MethodByMethodInfo)info).getCallingMethod().getModifiers()); 127 } 128 129 protected boolean hasTargetObject() 130 { 131 return !java.lang.reflect.Modifier.isStatic(((MethodByMethodInfo)info).getMethod().getModifiers()); 132 } 133 134 protected static CtClass createJoinpointBaseClass( 135 GeneratedAdvisorInstrumentor instrumentor, 136 long callingHash, 137 boolean hasCallingObject, 138 CtClass callingClass, 139 CtMethod targetMethod, 140 String classname, 141 long calledHash, 142 String ciname) throws NotFoundException, CannotCompileException 143 { 144 instrumentor.addJoinPointGeneratorFieldToGenAdvisor( 145 getJoinPointGeneratorFieldName(callingHash, classname, calledHash)); 146 147 BaseClassGenerator generator = new BaseClassGenerator(instrumentor, callingClass, callingHash, hasCallingObject, classname, targetMethod, calledHash, ciname); 148 return generator.generate(); 149 } 150 151 protected String getJoinPointGeneratorFieldName() 152 { 153 return getJoinPointGeneratorFieldName(callingMethodHash(), calledClass(), calledMethodHash()); 154 } 155 156 protected static String getInfoClassName(long callingHash, String classname, long calledHash) 157 { 158 return JOINPOINT_CLASS_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash); 159 } 160 161 protected static String getInfoFieldName(long callingHash, String classname, long calledHash) 162 { 163 return JOINPOINT_FIELD_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash); 164 } 165 166 protected static String getJoinPointGeneratorFieldName(long callingHash, String classname, long calledHash) 167 { 168 return GENERATOR_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash); 169 } 170 171 private static class BaseClassGenerator 172 { 173 GeneratedAdvisorInstrumentor instrumentor; 174 CtClass callingClass; 175 long callingHash; 176 boolean hasCallingObject; 177 String classname; 178 CtClass targetClass; 179 CtMethod targetMethod; 180 long calledHash; 181 String ciname; 182 boolean hasTargetObject; 183 184 CtClass jp; 185 CtMethod invokeJoinpointMethod; 186 CtConstructor publicConstructor; 187 CtConstructor protectedConstructor; 188 CtField targetField; 189 CtClass[] params; 190 CtClass methodInfoClass; 191 192 BaseClassGenerator( 193 GeneratedAdvisorInstrumentor instrumentor, 194 CtClass callingClass, 195 long callingHash, 196 boolean hasCallingObject, 197 String classname, 198 CtMethod targetMethod, 199 long calledHash, 200 String ciname) throws NotFoundException 201 { 202 this.instrumentor = instrumentor; 203 this.callingClass = callingClass; 204 this.callingHash = callingHash; 205 this.classname = classname; 206 this.hasCallingObject = hasCallingObject; 207 this.targetClass = instrumentor.forName(classname); 208 this.targetMethod = targetMethod; 209 this.calledHash = calledHash; 210 this.ciname = ciname; 211 this.params = targetMethod.getParameterTypes(); 212 methodInfoClass = instrumentor.forName(CallerTransformer.METHOD_BY_METHOD_INFO_CLASS_NAME); 213 hasTargetObject = !Modifier.isStatic(targetMethod.getModifiers()); 214 } 215 216 protected CtClass generate() throws CannotCompileException, NotFoundException 217 { 218 jp = setupClass(); 219 addArgumentsFieldsAndAccessors(); 220 if (hasTargetObject) 221 { 222 addTypedTargetField(); 223 } 224 addInvokeJoinpointMethod(); 225 addMethodInfoField(); 226 addPublicConstructor(); 227 addProtectedConstructor(); 228 addDispatchMethods(); 229 230 TransformerCommon.compileOrLoadClass(callingClass, jp); 231 return jp; 232 } 233 234 235 private CtClass setupClass()throws NotFoundException, CannotCompileException 236 { 237 String className = getInfoClassName(callingHash, targetClass.getName(), calledHash); 238 239 jp = TransformerCommon.makeNestedClass(callingClass, className, true); 241 int mod = jp.getModifiers(); 242 jp.setModifiers(mod | Modifier.PUBLIC); 243 244 CtClass invocation = INVOCATION_CT_TYPE; 245 jp.setSuperclass(invocation); 246 addUntransformableInterface(instrumentor, jp); 247 return jp; 248 } 249 250 private void addArgumentsFieldsAndAccessors() throws NotFoundException, CannotCompileException 251 { 252 OptimizedBehaviourInvocations.addArgumentFieldsToInvocation(jp, params); 253 OptimizedBehaviourInvocations.addSetArguments(instrumentor.getClassPool(), jp, params); 254 OptimizedBehaviourInvocations.addGetArguments(instrumentor.getClassPool(), jp, params); 255 } 256 257 private void addTypedTargetField()throws CannotCompileException 258 { 259 targetField = new CtField(targetClass, TARGET_FIELD, jp); 260 jp.addField(targetField); 261 targetField.setModifiers(Modifier.PROTECTED); 262 } 263 268 private void addPublicConstructor() throws CannotCompileException 269 { 270 publicConstructor = CtNewConstructor.make( 271 new CtClass[] {methodInfoClass}, 272 new CtClass[0], 273 "{super($1, null, null, $1.getInterceptors()); this." + INFO_FIELD + " = $1;}", 274 jp); 275 276 jp.addConstructor(publicConstructor); 277 } 278 279 283 protected void addProtectedConstructor() throws CannotCompileException 284 { 285 int offset = 1; 286 if (hasTargetObject) offset++; 287 if (hasCallingObject) offset++; 288 CtClass[] ctorParams = new CtClass[params.length + offset]; 289 290 int index = 0; 291 ctorParams[index++] = jp; 292 if (hasTargetObject) ctorParams[index++] = targetClass; 293 if (hasCallingObject) ctorParams[index] = callingClass; 294 System.arraycopy(params, 0, ctorParams, offset, params.length); 295 296 StringBuffer body = new StringBuffer (); 297 body.append("{"); 298 body.append(" this($1." + INFO_FIELD + ");"); 299 if (hasTargetObject) 300 { 301 body.append(" super.targetObject=$2;"); 302 body.append(" this.tgt=$2;"); 303 } 304 if (hasCallingObject) body.append(" super.callingObject=$" + (hasTargetObject ? 3 : 2) + ";"); 305 306 for (int i = offset ; i < ctorParams.length ; i++) 307 { 308 body.append(" arg" + (i - offset) + " = $" + (i + 1) + ";"); 309 } 310 311 body.append("}"); 312 protectedConstructor = CtNewConstructor.make( 313 ctorParams, 314 new CtClass[0], 315 body.toString(), 316 jp); 317 protectedConstructor.setModifiers(Modifier.PROTECTED); 318 319 jp.addConstructor(protectedConstructor); 320 321 } 322 323 private CtClass[] getInvokeJoinpointParameters() 324 { 325 if (!hasCallingObject && ! hasTargetObject) 326 { 327 return params; 328 } 329 330 int offset = 0; 331 if (hasTargetObject) offset++; 332 if (hasCallingObject) offset++; 333 CtClass[] invokeParams = new CtClass[params.length + offset]; 334 335 int index = 0; 336 if (hasTargetObject) invokeParams[index++] = targetClass; 337 if (hasCallingObject) invokeParams[index++] = callingClass; 338 System.arraycopy(params, 0, invokeParams, offset, params.length); 339 340 return invokeParams; 341 } 342 346 private CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException 347 { 348 invokeJoinpointMethod = CtNewMethod.make( 349 targetMethod.getReturnType(), 350 INVOKE_JOINPOINT, 351 getInvokeJoinpointParameters(), 352 targetMethod.getExceptionTypes(), 353 null, 354 jp); 355 356 invokeJoinpointMethod.setModifiers(Modifier.PROTECTED); 357 jp.addMethod(invokeJoinpointMethod); 358 return invokeJoinpointMethod; 359 } 360 361 private void addMethodInfoField()throws CannotCompileException 362 { 363 CtField infoField = new CtField(methodInfoClass, INFO_FIELD, jp); 364 infoField.setModifiers(javassist.Modifier.PROTECTED); jp.addField(infoField); 366 } 367 368 private void addDispatchMethods() throws CannotCompileException, NotFoundException 369 { 370 addInvokeNextDispatchMethod(); 371 if (hasCallingObject || hasTargetObject || params.length > 0) 372 { 373 addInvokeJoinPointDispatchMethod(); 374 } 375 376 addInvokeTargetMethod(); 377 } 378 379 private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException 380 { 381 final boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType); 383 384 StringBuffer parameters = new StringBuffer (); 385 for (int i = 0 ; i < params.length ; i++) 386 { 387 if (i > 0)parameters.append(", "); 388 parameters.append("arg" + i); 389 } 390 391 StringBuffer body = new StringBuffer ("{"); 392 393 if (hasTargetObject) 394 { 395 body.append(MethodExecutionTransformer.getAopReturnStr(isVoid) + TARGET_FIELD + "." + targetMethod.getName() + "(" + parameters + ");"); 396 } 397 else 398 { 399 body.append(MethodExecutionTransformer.getReturnStr(isVoid) + targetClass.getName() + "." + targetMethod.getName() + "(" + parameters + ");"); 400 } 401 402 body.append("}"); 403 try 404 { 405 CtMethod dispatch = CtNewMethod.make( 406 (isVoid) ? CtClass.voidType : targetMethod.getReturnType(), 407 JoinPointGenerator.DISPATCH, 408 EMPTY_CTCLASS_ARRAY, 409 targetMethod.getExceptionTypes(), 410 body.toString(), 411 jp); 412 dispatch.setModifiers(Modifier.PROTECTED); 413 jp.addMethod(dispatch); 414 } 415 catch (CannotCompileException e) 416 { 417 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e); 418 } 419 } 420 421 private void addInvokeJoinPointDispatchMethod() throws CannotCompileException, NotFoundException 422 { 423 final boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType); 425 CtClass[] invokeParams = getInvokeJoinpointParameters(); 426 427 final int offset = invokeParams.length - params.length; 428 StringBuffer parameters = new StringBuffer (); 429 for (int i = 0 ; i < params.length ; i++) 430 { 431 if (i > 0)parameters.append(", "); 432 parameters.append("$" + (i + offset + 1)); 433 } 434 435 StringBuffer body = new StringBuffer ("{"); 436 437 if (hasTargetObject) 438 { 439 body.append(MethodExecutionTransformer.getAopReturnStr(isVoid) + "$1." + targetMethod.getName() + "(" + parameters + ");"); 440 } 441 else 442 { 443 body.append(MethodExecutionTransformer.getReturnStr(isVoid) + targetClass.getName() + "." + targetMethod.getName() + "(" + parameters + ");"); 444 } 445 446 body.append("}"); 447 try 448 { 449 CtMethod dispatch = CtNewMethod.make( 450 (isVoid) ? CtClass.voidType : targetMethod.getReturnType(), 451 JoinPointGenerator.DISPATCH, 452 invokeParams, 453 targetMethod.getExceptionTypes(), 454 body.toString(), 455 jp); 456 dispatch.setModifiers(Modifier.PROTECTED); 457 jp.addMethod(dispatch); 458 } 459 catch (CannotCompileException e) 460 { 461 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, invokeParams), e); 462 } 463 } 464 465 private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException 466 { 467 CtMethod template = INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET); 468 469 boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType); 470 String body = (isVoid) ? "{dispatch(); return null;}" : "{return ($w)dispatch();}"; 471 472 CtMethod invokeTarget = CtNewMethod.make( 473 template.getReturnType(), 474 template.getName(), 475 template.getParameterTypes(), 476 template.getExceptionTypes(), 477 body, 478 jp); 479 jp.addMethod(invokeTarget); 480 } 481 } 482 } | Popular Tags |