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