1 22 package org.jboss.aop.instrument; 23 24 import java.lang.reflect.Field ; 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.FieldInfo; 37 import org.jboss.aop.GeneratedClassAdvisor; 38 import org.jboss.aop.JoinPointInfo; 39 import org.jboss.aop.advice.AdviceMethodProperties; 40 import org.jboss.aop.joinpoint.FieldReadInvocation; 41 import org.jboss.aop.joinpoint.FieldWriteInvocation; 42 import org.jboss.aop.util.JavassistToReflect; 43 import org.jboss.aop.util.ReflectToJavassist; 44 45 50 public class FieldJoinPointGenerator extends JoinPointGenerator 51 { 52 public static final String WRITE_GENERATOR_PREFIX = GENERATOR_PREFIX + "w_"; 53 public static final String READ_GENERATOR_PREFIX = GENERATOR_PREFIX + "r_"; 54 public static final String WRITE_JOINPOINT_FIELD_PREFIX = JOINPOINT_FIELD_PREFIX + "w_"; 55 public static final String READ_JOINPOINT_FIELD_PREFIX = JOINPOINT_FIELD_PREFIX + "r_"; 56 public static final String WRITE_JOINPOINT_CLASS_PREFIX = JOINPOINT_CLASS_PREFIX + "w_"; 57 public static final String READ_JOINPOINT_CLASS_PREFIX = JOINPOINT_CLASS_PREFIX + "r_"; 58 private static final Class READ_INVOCATION_TYPE = FieldReadInvocation.class; 59 private static final Class WRITE_INVOCATION_TYPE = FieldWriteInvocation.class; 60 private static final CtClass READ_INVOCATION_CT_TYPE; 61 private static final CtClass WRITE_INVOCATION_CT_TYPE; 62 static 63 { 64 try 65 { 66 READ_INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(READ_INVOCATION_TYPE); 67 WRITE_INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(WRITE_INVOCATION_TYPE); 68 } 69 catch (NotFoundException e) 70 { 71 throw new RuntimeException (e); 72 } 73 } 74 75 public FieldJoinPointGenerator(GeneratedClassAdvisor advisor, JoinPointInfo info) 76 { 77 super(advisor, info); 78 } 79 80 protected void initialiseJoinPointNames() 81 { 82 joinpointClassName = 83 getInfoClassName(fieldName(), read()); 84 85 joinpointFieldName = 86 getInfoFieldName(fieldName(), read()); 87 } 88 89 private String fieldName() 90 { 91 return ((FieldInfo)info).getAdvisedField().getName(); 92 } 93 94 private boolean read() 95 { 96 return ((FieldInfo)info).isRead(); 97 } 98 99 protected boolean isVoid() 100 { 101 return !((FieldInfo)info).isRead(); 102 } 103 104 protected Class getReturnType() 105 { 106 if (!read()) 107 { 108 return null; 109 } 110 return ((FieldInfo)super.info).getAdvisedField().getType(); 111 } 112 113 protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup) 114 { 115 Field field = ((FieldInfo)info).getAdvisedField(); 116 return new AdviceMethodProperties( 117 setup.getAspectClass(), 118 setup.getAdviceName(), 119 info.getClass(), 120 (read()) ? READ_INVOCATION_TYPE : WRITE_INVOCATION_TYPE, 121 (read()) ? getReturnType() : Void.TYPE, 122 (read()) ? new Class [] {} : new Class [] {field.getType()}, 123 null); 124 } 125 126 protected CtClass[] getJoinpointParameters() throws NotFoundException 127 { 128 if (isVoid()) return new CtClass[0]; 129 130 CtClass type = ReflectToJavassist.fieldToJavassist(((FieldInfo)super.info).getAdvisedField()).getType(); 131 return new CtClass[] {type}; 132 } 133 134 protected boolean hasTargetObject() 135 { 136 return !Modifier.isStatic(((FieldInfo)info).getAdvisedField().getModifiers()); 137 } 138 139 protected String getJoinPointGeneratorFieldName() 140 { 141 return getJoinPointGeneratorFieldName(fieldName(), read()); 142 } 143 144 protected static String getInfoFieldName(String fieldName, boolean read) 145 { 146 if (read) 147 { 148 return READ_JOINPOINT_FIELD_PREFIX + fieldName; 149 } 150 else 151 { 152 return WRITE_JOINPOINT_FIELD_PREFIX + fieldName; 153 } 154 } 155 156 private static String getInfoClassName(String fieldName, boolean read) 157 { 158 if (read) 159 { 160 return READ_JOINPOINT_CLASS_PREFIX + fieldName; 161 } 162 else 163 { 164 return WRITE_JOINPOINT_CLASS_PREFIX + fieldName; 165 } 166 } 167 168 public static String getJoinPointGeneratorFieldName(String fieldName, boolean read) 169 { 170 if (read) 171 { 172 return READ_GENERATOR_PREFIX + fieldName; 173 } 174 else 175 { 176 return WRITE_GENERATOR_PREFIX + fieldName; 177 } 178 } 179 180 protected static CtClass createReadJoinpointBaseClass( 181 GeneratedAdvisorInstrumentor instrumentor, 182 CtClass advisedClass, 183 CtField advisedField, 184 String finame, 185 int index)throws NotFoundException, CannotCompileException 186 { 187 instrumentor.addJoinPointGeneratorFieldToGenAdvisor( 188 getJoinPointGeneratorFieldName(advisedField.getName(), true)); 189 190 BaseClassGenerator factory = new ReadBaseClassGenerator(instrumentor, advisedClass, advisedField, finame, index); 191 return factory.generate(); 192 } 193 194 protected static CtClass createWriteJoinpointBaseClass( 195 GeneratedAdvisorInstrumentor instrumentor, 196 CtClass advisedClass, 197 CtField advisedField, 198 String finame, 199 int index)throws NotFoundException, CannotCompileException 200 { 201 instrumentor.addJoinPointGeneratorFieldToGenAdvisor( 202 getJoinPointGeneratorFieldName(advisedField.getName(), false)); 203 204 BaseClassGenerator factory = new WriteBaseClassGenerator(instrumentor, advisedClass, advisedField, finame, index); 205 return factory.generate(); 206 } 207 208 209 static abstract class BaseClassGenerator 210 { 211 GeneratedAdvisorInstrumentor instrumentor; 212 CtClass advisedClass; 213 CtField advisedField; 214 String finame; 215 int index; 216 boolean hasTargetObject; 217 218 CtClass jp; 219 CtMethod invokeJoinpointMethod; 220 CtConstructor publicConstructor; 221 CtConstructor protectedConstructor; 222 CtField targetField; 223 CtClass fieldType; 224 CtClass fieldInfoClass; 225 boolean read; 226 227 BaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass, 228 CtField advisedField, String finame, int index, boolean read) throws NotFoundException 229 { 230 this.instrumentor = instrumentor; 231 this.advisedClass = advisedClass; 232 this.advisedField = advisedField; 233 this.finame = finame; 234 this.fieldType = advisedField.getType(); 235 this.read = read; 236 fieldInfoClass = instrumentor.forName(FieldAccessTransformer.FIELD_INFO_CLASS_NAME); 237 hasTargetObject = !Modifier.isStatic(advisedField.getModifiers()); 238 } 239 240 protected CtClass generate() throws CannotCompileException, NotFoundException 241 { 242 jp = setupClass(); 243 if (hasTargetObject) 244 { 245 addTypedTargetField(); 246 } 247 addInvokeJoinpointMethod(); 248 addFieldInfoField(); 249 addPublicConstructor(); 250 addProtectedConstructor(); 251 addDispatchMethods(); 252 253 TransformerCommon.compileOrLoadClass(advisedClass, jp); 254 return jp; 255 } 256 257 private static String debugFields(CtClass clazz) throws NotFoundException 258 { 259 StringBuffer sb = new StringBuffer (); 260 sb.append(clazz.getName()); 261 CtField[] fields = clazz.getFields(); 262 for (int i = 0 ; i < fields.length ; i++) 263 { 264 sb.append("\n\t\t\t\t" + Modifier.toString(fields[i].getModifiers()) + " " + fields[i].getName() + " " + fields[i].getType()); 265 } 266 267 return sb.toString(); 268 } 269 270 private CtClass setupClass()throws NotFoundException, CannotCompileException 271 { 272 String className = getInfoClassName(advisedField.getName(), read); 273 274 CtClass superClass = (read) ? READ_INVOCATION_CT_TYPE : WRITE_INVOCATION_CT_TYPE; 276 jp = TransformerCommon.makeNestedClass(advisedClass, className, true, Modifier.PUBLIC | Modifier.STATIC, superClass); 277 addUntransformableInterface(instrumentor, jp); 278 return jp; 279 } 280 281 protected abstract CtClass getSuperClass() throws NotFoundException; 282 283 private void addTypedTargetField()throws CannotCompileException 284 { 285 targetField = new CtField(advisedClass, TARGET_FIELD, jp); 286 jp.addField(targetField); 287 targetField.setModifiers(Modifier.PROTECTED); 288 } 289 290 295 private void addPublicConstructor() throws CannotCompileException 296 { 297 publicConstructor = CtNewConstructor.make( 298 new CtClass[] {fieldInfoClass}, 299 new CtClass[0], 300 "{super($1, $1.getInterceptors()); this." + INFO_FIELD + " = $1;}", 301 jp); 302 303 jp.addConstructor(publicConstructor); 304 } 305 306 310 protected void addProtectedConstructor() throws CannotCompileException, NotFoundException 311 { 312 313 protectedConstructor = CtNewConstructor.make( 314 createProtectedCtorParams(), 315 new CtClass[0], 316 createProtectedCtorBody(), 317 jp); 318 protectedConstructor.setModifiers(Modifier.PROTECTED); 319 320 jp.addConstructor(protectedConstructor); 321 } 322 323 protected abstract CtClass[] createProtectedCtorParams() throws NotFoundException; 324 protected abstract String createProtectedCtorBody(); 325 protected abstract CtClass[] getInvokeJoinPointParams() throws NotFoundException; 326 330 protected abstract CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException; 331 332 private void addFieldInfoField()throws CannotCompileException 333 { 334 CtField infoField = new CtField(fieldInfoClass, INFO_FIELD, jp); 335 infoField.setModifiers(javassist.Modifier.PROTECTED); jp.addField(infoField); 337 } 338 339 private void addDispatchMethods() throws CannotCompileException, NotFoundException 340 { 341 addInvokeNextDispatchMethod(); 342 addInvokeJoinPointDispatchMethod(); 343 addInvokeTargetMethod(); 344 } 345 346 private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException 347 { 348 350 String body = createInvokeNextDispatchMethodBody(); 351 352 try 353 { 354 CtMethod dispatch = CtNewMethod.make( 355 (read) ? advisedField.getType() : CtClass.voidType, 356 JoinPointGenerator.DISPATCH, 357 EMPTY_CTCLASS_ARRAY, 358 EMPTY_CTCLASS_ARRAY, 359 body, 360 jp); 361 dispatch.setModifiers(Modifier.PROTECTED); 362 jp.addMethod(dispatch); 363 } 364 catch (CannotCompileException e) 365 { 366 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e); 367 } 368 } 369 370 protected abstract String createInvokeNextDispatchMethodBody() throws NotFoundException; 371 372 protected void addInvokeJoinPointDispatchMethod() throws NotFoundException, CannotCompileException 373 { 374 CtClass[] params = getInvokeJoinPointParams(); 375 if (params.length == 0) 376 { 377 return; 378 } 379 380 382 String body = createInvokeJoinPointDispatchMethodBody(); 383 384 try 385 { 386 CtMethod dispatch = CtNewMethod.make( 387 (read) ? advisedField.getType() : CtClass.voidType, 388 JoinPointGenerator.DISPATCH, 389 params, 390 new CtClass[0], 391 body, 392 jp); 393 dispatch.setModifiers(Modifier.PROTECTED); 394 jp.addMethod(dispatch); 395 } 396 catch (CannotCompileException e) 397 { 398 throw new RuntimeException ("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, params), e); 399 } 400 } 401 402 protected abstract String createInvokeJoinPointDispatchMethodBody() throws NotFoundException; 403 404 private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException 405 { 406 CtMethod template = READ_INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET); 407 408 String body = (read) ? "{return ($w)dispatch();}" : "{dispatch(); return null;}" ; 409 410 CtMethod invokeTarget = CtNewMethod.make( 411 template.getReturnType(), 412 template.getName(), 413 template.getParameterTypes(), 414 template.getExceptionTypes(), 415 body, 416 jp); 417 jp.addMethod(invokeTarget); 418 } 419 420 } 421 422 private static class ReadBaseClassGenerator extends BaseClassGenerator 423 { 424 ReadBaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass, 425 CtField advisedField, String finame, int index) throws NotFoundException 426 { 427 super(instrumentor, advisedClass, advisedField, finame, index, true); 428 } 429 430 protected CtClass getSuperClass() throws NotFoundException 431 { 432 return READ_INVOCATION_CT_TYPE; 433 } 434 435 protected CtClass[] createProtectedCtorParams() throws NotFoundException 436 { 437 CtClass[] ctorParams = (hasTargetObject) ? new CtClass[2] : new CtClass[1]; 438 ctorParams[0] = jp; 439 if (hasTargetObject) ctorParams[1] = advisedClass; 440 441 return ctorParams; 442 } 443 444 protected String createProtectedCtorBody() 445 { 446 StringBuffer body = new StringBuffer (); 447 body.append("{"); 448 body.append(" this($1." + INFO_FIELD + ");"); 449 450 if (hasTargetObject) 451 { 452 body.append(" this." + TARGET_FIELD + " = $2;"); 453 body.append(" super.setTargetObject($2);"); 454 } 455 456 body.append("}"); 457 return body.toString(); 458 } 459 460 protected CtClass[] getInvokeJoinPointParams() throws NotFoundException 461 { 462 return (hasTargetObject) ? new CtClass[] {advisedClass} : new CtClass[0]; 463 } 464 465 protected CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException 466 { 467 invokeJoinpointMethod = CtNewMethod.make( 468 advisedField.getType(), 469 INVOKE_JOINPOINT, 470 getInvokeJoinPointParams(), 471 new CtClass[0], 472 null, 473 jp); 474 invokeJoinpointMethod.setModifiers(Modifier.PROTECTED); 475 jp.addMethod(invokeJoinpointMethod); 476 477 return invokeJoinpointMethod; 478 } 479 480 protected String createInvokeNextDispatchMethodBody() 481 { 482 return (hasTargetObject) ? 483 "{return " + TARGET_FIELD + "." + advisedField.getName() + ";}" : 484 "{return " + advisedClass.getName() + "." + advisedField.getName() + ";}"; 485 } 486 487 protected String createInvokeJoinPointDispatchMethodBody() 488 { 489 return (hasTargetObject) ? 490 "{return " + "$1." + advisedField.getName() + ";}" : 491 "{return " + advisedClass.getName() + "." + advisedField.getName() + ";}"; 492 } 493 } 494 495 private static class WriteBaseClassGenerator extends BaseClassGenerator 496 { 497 WriteBaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass, 498 CtField advisedField, String finame, int index) throws NotFoundException 499 { 500 super(instrumentor, advisedClass, advisedField, finame, index, false); 501 } 502 503 protected CtClass getSuperClass() throws NotFoundException 504 { 505 return WRITE_INVOCATION_CT_TYPE; 506 } 507 508 protected CtClass[] createProtectedCtorParams() throws NotFoundException 509 { 510 CtClass[] ctorParams = (hasTargetObject) ? new CtClass[3] : new CtClass[2]; 511 ctorParams[0] = jp; 512 if (hasTargetObject) 513 { 514 ctorParams[1] = advisedClass; 515 ctorParams[2] = advisedField.getType(); 516 } 517 else 518 { 519 ctorParams[1] = advisedField.getType(); 520 } 521 522 return ctorParams; 523 } 524 525 protected String createProtectedCtorBody() 526 { 527 StringBuffer body = new StringBuffer (); 528 body.append("{"); 529 body.append(" this($1." + INFO_FIELD + ");"); 530 531 if (hasTargetObject) 532 { 533 body.append(" this." + TARGET_FIELD + " = $2;"); 534 body.append(" super.setTargetObject($2);"); 535 body.append(" super.value = ($w)$3;"); 536 } 537 else 538 { 539 body.append(" super.value = ($w)$2;"); 540 } 541 542 body.append("}"); 543 return body.toString(); 544 } 545 546 protected CtClass[] getInvokeJoinPointParams() throws NotFoundException 547 { 548 return (hasTargetObject) ? new CtClass[] {advisedClass, advisedField.getType()} : new CtClass[] {advisedField.getType()}; 549 } 550 551 protected CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException 552 { 553 invokeJoinpointMethod = CtNewMethod.make( 554 CtClass.voidType, 555 JoinPointGenerator.INVOKE_JOINPOINT, 556 getInvokeJoinPointParams(), 557 new CtClass[0], 558 null, 559 jp); 560 invokeJoinpointMethod.setModifiers(Modifier.PROTECTED); 561 jp.addMethod(invokeJoinpointMethod); 562 563 return invokeJoinpointMethod; 564 } 565 566 protected String createInvokeNextDispatchMethodBody() throws NotFoundException 567 { 568 CtClass type = advisedField.getType(); 569 String value = JavassistToReflect.castInvocationValueToTypeString(type); 570 571 return 572 "{" + 573 ((hasTargetObject) ? 574 TARGET_FIELD + "." + advisedField.getName() + " = " + value: 575 advisedClass.getName() + "." + advisedField.getName() + " = " + value) + 576 577 ((hasTargetObject) ? 578 "return " + TARGET_FIELD + "." + advisedField.getName() + ";" : 579 "return " + advisedClass.getName() + "." + advisedField.getName() + ";") + 580 "}"; 581 } 582 583 protected String createInvokeJoinPointDispatchMethodBody() 584 { 585 return (hasTargetObject) ? 586 "{$1." + advisedField.getName() + " = $2;}" : 587 "{" + advisedClass.getName() + "." + advisedField.getName() + " = $1;}"; 588 } 589 } 590 } 591 | Popular Tags |