1 22 package org.jboss.aop.instrument; 23 24 import java.lang.reflect.Method ; 25 import java.lang.reflect.Modifier ; 26 27 import javassist.CannotCompileException; 28 import javassist.CtClass; 29 import javassist.CtConstructor; 30 import javassist.CtField; 31 import javassist.CtMethod; 32 import javassist.CtNewConstructor; 33 import javassist.CtNewMethod; 34 import javassist.NotFoundException; 35 36 import org.jboss.aop.GeneratedClassAdvisor; 37 import org.jboss.aop.MethodInfo; 38 import org.jboss.aop.advice.AdviceMethodProperties; 39 import org.jboss.aop.joinpoint.MethodInvocation; 40 import org.jboss.aop.util.ReflectToJavassist; 41 42 47 public class MethodJoinPointGenerator extends JoinPointGenerator 48 { 49 private static final Class INVOCATION_TYPE = MethodInvocation.class; 50 private static final CtClass INVOCATION_CT_TYPE; 51 static 52 { 53 try 54 { 55 INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(INVOCATION_TYPE); 56 } 57 catch (NotFoundException e) 58 { 59 throw new RuntimeException (e); 60 } 61 } 62 63 public MethodJoinPointGenerator(GeneratedClassAdvisor advisor, MethodInfo info) 64 { 65 super(advisor, info); 66 } 67 68 protected void initialiseJoinPointNames() 69 { 70 joinpointClassName = getInfoClassName( 71 advisedMethodName(), 72 methodHash()); 73 74 joinpointFieldName = getInfoFieldName( 75 advisedMethodName(), 76 methodHash()); 77 } 78 79 private String advisedMethodName() 80 { 81 return ((MethodInfo)info).getAdvisedMethod().getName(); 82 } 83 84 private long methodHash() 85 { 86 return ((MethodInfo)info).getHash(); 87 } 88 89 protected boolean isVoid() 90 { 91 return ((MethodInfo)info).getUnadvisedMethod().getReturnType().equals(Void.TYPE); 92 } 93 94 protected Class getReturnType() 95 { 96 if (isVoid()) return null; 97 return ((MethodInfo)info).getUnadvisedMethod().getReturnType(); 98 } 99 100 protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup) 101 { 102 Method method = ((MethodInfo)info).getAdvisedMethod(); 103 return new AdviceMethodProperties( 104 setup.getAspectClass(), 105 setup.getAdviceName(), 106 info.getClass(), 107 INVOCATION_TYPE, 108 method.getReturnType(), 109 method.getParameterTypes(), 110 method.getExceptionTypes()); 111 } 112 113 114 protected boolean hasTargetObject() 115 { 116 return !Modifier.isStatic(((MethodInfo)info).getAdvisedMethod().getModifiers()); 117 } 118 119 protected String getInfoName() 120 { 121 return MethodExecutionTransformer.getMethodInfoFieldName( 122 ((MethodInfo)info).getAdvisedMethod().getName(), ((MethodInfo)info).getHash()); 123 } 124 125 protected static CtClass createJoinpointBaseClass( 126 GeneratedAdvisorInstrumentor instrumentor, 127 CtClass advisedClass, 128 CtMethod targetMethod, 129 String miname, 130 String originalMethodName, 131 String wrappedMethodName, 132 long hash) throws CannotCompileException, NotFoundException 133 { 134 instrumentor.addJoinPointGeneratorFieldToGenAdvisor( 135 getJoinPointGeneratorFieldName(originalMethodName, hash)); 136 137 BaseClassGenerator factory = new BaseClassGenerator(instrumentor, advisedClass, targetMethod, miname, originalMethodName, wrappedMethodName, hash); 138 return factory.generate(); 139 } 140 141 protected String getJoinPointGeneratorFieldName() 142 { 143 return getJoinPointGeneratorFieldName(advisedMethodName(), methodHash()); 144 } 145 146 protected static String getInfoFieldName(String methodName, long hash) 147 { 148 return JOINPOINT_FIELD_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash); 149 } 150 151 private static String getInfoClassName(String methodName, long hash) 152 { 153 return JOINPOINT_CLASS_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash); 154 } 155 156 protected static String getJoinPointGeneratorFieldName(String methodName, long hash) 157 { 158 return GENERATOR_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash); 159 } 160 161 private static class BaseClassGenerator 162 { 163 GeneratedAdvisorInstrumentor instrumentor; 164 CtClass advisedClass; 165 CtMethod advisedMethod; 166 String miname; 167 String originalMethodName; 168 String wrappedMethodName; 169 long hash; 170 boolean hasTargetObject; 171 172 CtClass jp; 173 CtMethod invokeJoinpointMethod; 174 CtConstructor publicConstructor; 175 CtConstructor protectedConstructor; 176 CtField targetField; 177 CtClass[] originalParams; 178 CtClass[] params; 179 CtClass methodInfoClass; 180 181 BaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass, 182 CtMethod targetMethod, String miname, 183 String originalMethodName, String wrappedMethodName,long hash) throws NotFoundException 184 { 185 this.instrumentor = instrumentor; 186 this.advisedClass = advisedClass; 187 this.advisedMethod = targetMethod; 188 this.miname = miname; 189 this.originalMethodName = originalMethodName; 190 this.wrappedMethodName = wrappedMethodName; 191 this.hash = hash; 192 this.originalParams = targetMethod.getParameterTypes(); 193 this.params = GeneratedAdvisorMethodExecutionTransformer.addTargetToParamsForNonStaticMethod(advisedClass, targetMethod); 194 methodInfoClass = instrumentor.forName(MethodExecutionTransformer.METHOD_INFO_CLASS_NAME); 195 hasTargetObject = !Modifier.isStatic(advisedMethod.getModifiers()); 196 } 197 198 protected CtClass generate() throws CannotCompileException, NotFoundException 199 { 200 jp = setupClass(); 201 addArgumentsFieldsAndAccessors(); 202 if (hasTargetObject) 203 { 204 addTypedTargetField(); 205 } 206 addInvokeJoinpointMethod(); 207 addMethodInfoField(); 208 addDefaultConstructor(); 209 addPublicConstructor(); 210 addProtectedConstructor(); 211 addDispatchMethods(); 212 213 TransformerCommon.compileOrLoadClass(advisedClass, jp); 214 return jp; 215 } 216 217 218 private CtClass setupClass()throws NotFoundException, CannotCompileException 219 { 220 String className = getInfoClassName(originalMethodName, hash); 221 222 jp = TransformerCommon.makeNestedClass(advisedClass, className, true); 224 int mod = jp.getModifiers(); 225 jp.setModifiers(mod | Modifier.PUBLIC); 226 227 CtClass methodInvocation = INVOCATION_CT_TYPE; 228 jp.setSuperclass(methodInvocation); 229 addUntransformableInterface(instrumentor, jp); 230 231 return jp; 232 } 233 234 private void addArgumentsFieldsAndAccessors() throws NotFoundException, CannotCompileException 235 { 236 OptimizedBehaviourInvocations.addArgumentFieldsToInvocation(jp, originalParams); 237 OptimizedBehaviourInvocations.addSetArguments(instrumentor.getClassPool(), jp, originalParams); 238 OptimizedBehaviourInvocations.addGetArguments(instrumentor.getClassPool(), jp, originalParams, true); 240 } 241 242 private void addTypedTargetField()throws CannotCompileException 243 { 244 targetField = new CtField(advisedClass, TARGET_FIELD, jp); 245 jp.addField(targetField); 246 targetField.setModifiers(Modifier.PROTECTED | Modifier.TRANSIENT); 247 } 248 249 252 private void addDefaultConstructor() throws CannotCompileException 253 { 254 CtConstructor defaultConstructor = CtNewConstructor.defaultConstructor(jp); 255 jp.addConstructor(defaultConstructor); 256 } 257 258 263 private void addPublicConstructor() throws CannotCompileException 264 { 265 publicConstructor = CtNewConstructor.make( 266 new CtClass[] {methodInfoClass}, 267 new CtClass[0], 268 "{super($1, $1.getInterceptors()); this." + INFO_FIELD + " = $1;}", 269 jp); 270 271 jp.addConstructor(publicConstructor); 272 } 273 274 278 protected void addProtectedConstructor() throws CannotCompileException 279 { 280 CtClass[] ctorParams = new CtClass[params.length + 1]; 281 ctorParams[0] = jp; 282 System.arraycopy(params, 0, ctorParams, 1, params.length); 283 284 StringBuffer body = new StringBuffer (); 285 body.append("{"); 286 body.append(" this($1." + INFO_FIELD + ");"); 287 288 int offset = 1; 289 if (hasTargetObject) 290 { 291 body.append(" this." + TARGET_FIELD + " = $2;"); 292 body.append(" super.setTargetObject($2);"); 293 offset = 2; 294 } 295 296 for (int i = offset ; i < ctorParams.length ; i++) 297 { 298 body.append(" arg" + (i - offset) + " = $" + (i + 1) + ";"); 299 } 300 301 body.append("}"); 302 protectedConstructor = CtNewConstructor.make( 303 ctorParams, 304 new CtClass[0], 305 body.toString(), 306 jp); 307 protectedConstructor.setModifiers(Modifier.PROTECTED); 308 309 jp.addConstructor(protectedConstructor); 310 311 } 312 313 317 private CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException 318 { 319 invokeJoinpointMethod = CtNewMethod.make( 320 advisedMethod.getReturnType(), 321 INVOKE_JOINPOINT, 322 params, 323 advisedMethod.getExceptionTypes(), 324 null, 325 jp); 326 invokeJoinpointMethod.setModifiers(Modifier.PROTECTED); 327 jp.addMethod(invokeJoinpointMethod); 328 return invokeJoinpointMethod; 329 } 330 331 private void addMethodInfoField()throws CannotCompileException 332 { 333 CtField infoField = new CtField(methodInfoClass, INFO_FIELD, jp); 334 jp.addField(infoField); 335 infoField.setModifiers(Modifier.PROTECTED | Modifier.TRANSIENT); } 337 338 private void addDispatchMethods() throws CannotCompileException, NotFoundException 339 { 340 addInvokeNextDispatchMethod(); 341 342 if (params.length > 0) 343 { 344 addInvokeJoinPointDispatchMethod(); 345 } 346 347 addInvokeTargetMethod(); 348 } 349 350 private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException 351 { 352 354 StringBuffer parameters = new StringBuffer (); 355 for (int i = 0 ; i < originalParams.length ; i++) 356 { 357 if (i > 0)parameters.append(", "); 358 parameters.append("arg" + i); 359 } 360 361 String body = (!hasTargetObject) ? 362 "{" + MethodExecutionTransformer.getReturnStr(advisedMethod) + advisedClass.getName() + "." + wrappedMethodName + "(" + parameters + ");}" : 363 "{" + MethodExecutionTransformer.getAopReturnStr(advisedMethod) + TARGET_FIELD + "." + wrappedMethodName + "(" + parameters + ");}"; 364 365 try 366 { 367 CtMethod dispatch = CtNewMethod.make( 368 advisedMethod.getReturnType(), 369 JoinPointGenerator.DISPATCH, 370 EMPTY_CTCLASS_ARRAY, 371 advisedMethod.getExceptionTypes(), 372 body, 373 jp); 374 dispatch.setModifiers(Modifier.PROTECTED); 375 jp.addMethod(dispatch); 376 } 377 catch (CannotCompileException e) 378 { 379 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e); 380 } 381 } 382 383 private void addInvokeJoinPointDispatchMethod() throws CannotCompileException, NotFoundException 384 { 385 387 int offset = hasTargetObject ? 1 : 0; 388 StringBuffer parameters = new StringBuffer (); 389 for (int i = 0 ; i < originalParams.length ; i++) 390 { 391 if (i > 0)parameters.append(", "); 392 parameters.append("$" + (i + offset + 1)); 393 } 394 395 String body = (!hasTargetObject) ? 396 "{" + MethodExecutionTransformer.getReturnStr(advisedMethod) + advisedClass.getName() + "." + wrappedMethodName + "(" + parameters + ");}" : 397 "{" + MethodExecutionTransformer.getAopReturnStr(advisedMethod) + "$1." + wrappedMethodName + "(" + parameters + ");}"; 398 399 400 try 401 { 402 CtMethod dispatch = CtNewMethod.make( 403 advisedMethod.getReturnType(), 404 JoinPointGenerator.DISPATCH, 405 params, 406 advisedMethod.getExceptionTypes(), 407 body, 408 jp); 409 dispatch.setModifiers(Modifier.PROTECTED); 410 jp.addMethod(dispatch); 411 } 412 catch (CannotCompileException e) 413 { 414 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, params), e); 415 } 416 } 417 418 private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException 419 { 420 CtMethod template = INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET); 421 422 boolean isVoid = advisedMethod.getReturnType().equals(CtClass.voidType); 423 String body = (isVoid) ? "{dispatch(); return null;}" : "{return ($w)dispatch();}"; 424 425 CtMethod invokeTarget = CtNewMethod.make( 426 template.getReturnType(), 427 template.getName(), 428 template.getParameterTypes(), 429 template.getExceptionTypes(), 430 body, 431 jp); 432 jp.addMethod(invokeTarget); 433 } 434 } 435 } 436 | Popular Tags |