1 22 package org.jboss.aop.instrument; 23 24 import java.util.Collection ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import org.jboss.aop.AspectManager; 28 import org.jboss.aop.ClassAdvisor; 29 import org.jboss.aop.classpool.AOPClassPool; 30 import org.jboss.aop.util.Advisable; 31 32 import javassist.CannotCompileException; 33 import javassist.ClassPool; 34 import javassist.CodeConverter; 35 import javassist.CtClass; 36 import javassist.CtField; 37 import javassist.CtMethod; 38 import javassist.CtNewMethod; 39 import javassist.Modifier; 40 import javassist.NotFoundException; 41 import javassist.expr.ExprEditor; 42 import javassist.expr.FieldAccess; 43 44 47 public abstract class FieldAccessTransformer implements CodeConversionObserver 48 { 49 51 final static String FIELD_INFO_CLASS_NAME = "org.jboss.aop.FieldInfo"; 52 53 Instrumentor instrumentor; 55 boolean optimize; 56 private Codifier codifier; 57 private JoinpointClassifier classifier; 58 59 protected static final String [] transformations = new String [] {"get", "set"}; 62 protected static final int GET_INDEX = 0; 63 protected static final int SET_INDEX = 1; 64 protected static final WrapperTransformer wrapper = new WrapperTransformer(transformations); 65 66 protected FieldAccessTransformer(Instrumentor instrumentor) 68 { 69 this.instrumentor = instrumentor; 70 this.optimize = AspectManager.optimize; 71 this.codifier = new Codifier(); 72 this.classifier = instrumentor.joinpointClassifier; 73 } 74 75 77 protected void buildFieldWrappers(CtClass clazz, ClassAdvisor advisor) throws NotFoundException, CannotCompileException 78 { 79 List fields = Instrumentor.getAdvisableFields(clazz); 80 81 int fieldIndex = fieldOffset(clazz.getSuperclass()); 82 JoinpointClassification[] classificationGet = classifyFieldGet(clazz, advisor); 83 JoinpointClassification[] classificationSet = classifyFieldSet(clazz, advisor); 84 Iterator it = fields.iterator(); 85 boolean skipFieldInterception = true; 86 for (int index = 0; it.hasNext(); index++, fieldIndex++) 87 { 88 CtField field = (CtField) it.next(); 89 90 if (!isPrepared(classificationGet[index]) && !isPrepared(classificationSet[index])) 91 { 92 continue; 93 } 94 95 if (!javassist.Modifier.isPrivate(field.getModifiers())) 96 { 97 skipFieldInterception = false; 98 } 99 100 doBuildFieldWrappers(clazz, field, fieldIndex, classificationGet[index], classificationSet[index]); 101 } 102 103 if (skipFieldInterception) 104 { 105 advisor.getManager().skipFieldAccess(clazz.getName()); 106 } 107 else 108 { 109 advisor.getManager().addFieldInterceptionMarker(clazz.getName()); 110 } 111 112 } 113 114 protected boolean isPrepared(JoinpointClassification classification) 115 { 116 return classification != JoinpointClassification.NOT_INSTRUMENTED; 117 } 118 119 protected abstract void doBuildFieldWrappers(CtClass clazz, CtField field, int index, JoinpointClassification classificationGet, JoinpointClassification classificationSet) throws NotFoundException, CannotCompileException; 120 129 public boolean replaceFieldAccess(List fields, CtClass clazz, ClassAdvisor fieldsAdvisor) throws NotFoundException 130 { 131 CodeConverter converter = instrumentor.getCodeConverter(); 132 boolean converted = false; 133 Iterator it = fields.iterator(); 134 while (it.hasNext()) 135 { 136 CtField field = (CtField) it.next(); 137 if (!Modifier.isPrivate(field.getModifiers()) && Advisable.isAdvisable(field)) 138 { 139 JoinpointClassification fieldGetClassification = classifier.classifyFieldGet(field, fieldsAdvisor); 140 141 if (fieldGetClassification.equals(JoinpointClassification.WRAPPED)) 142 { 143 converted = true; 144 converter.replaceFieldRead(field, clazz, fieldRead(field.getName())); 145 } 146 JoinpointClassification fieldSetClassification = classifier.classifyFieldSet(field, fieldsAdvisor); 147 if (fieldSetClassification.equals(JoinpointClassification.WRAPPED)) 148 { 149 converted = true; 150 converter.replaceFieldWrite(field, clazz, fieldWrite(field.getName())); 151 } 152 } 153 } 154 return converted; 155 } 156 157 165 public void wrap(CtClass clazz, Collection fieldsGet, Collection fieldsSet) throws CannotCompileException, NotFoundException 166 { 167 List advisableFields = Instrumentor.getAdvisableFields(clazz); 168 CtField[] fields = new CtField[advisableFields.size()]; 169 fields = (CtField[] ) advisableFields.toArray(fields); 170 for (Iterator iterator = fieldsGet.iterator(); iterator.hasNext(); ) 171 { 172 int fieldIndex = ((Integer ) iterator.next()).intValue(); 173 CtField field = fields[fieldIndex]; 174 if (wrapper.isNotPrepared(field, GET_INDEX)) 175 { 176 continue; 177 } 178 wrapper.wrap(field, GET_INDEX); 180 String code = "{" + field.getType().getName() + " var; return var;}"; 182 CtMethod method = getWrapperReadMethod(field, clazz); 183 method.setBody(code); 184 code = getWrapperBody(clazz, field, true, fieldIndex); 185 if (!Modifier.isPrivate(field.getModifiers())) 186 { 187 instrumentor.converter.replaceFieldRead(field, clazz, fieldRead(field.getName())); 188 codifier.addPendingCode(method, code); 189 } 190 else 191 { 192 replaceFieldAccessInternally(clazz, field, true, false, fieldIndex); 193 method.setBody(code); 194 } 195 } 196 for (Iterator iterator = fieldsSet.iterator(); iterator.hasNext(); ) 197 { 198 int fieldIndex = ((Integer ) iterator.next()).intValue(); 199 CtField field = fields[fieldIndex]; 200 if (wrapper.isNotPrepared(field, SET_INDEX)) 201 { 202 continue; 203 } 204 wrapper.wrap(field, SET_INDEX); 206 String code = "{ }"; 208 CtMethod method = getWrapperWriteMethod(field, clazz); 209 method.setBody(code); 210 code = getWrapperBody(clazz, field, false, fieldIndex); 211 if (!Modifier.isPrivate(field.getModifiers())) 212 { 213 instrumentor.converter.replaceFieldWrite(field, clazz, fieldWrite(field.getName())); 214 codifier.addPendingCode(method, code); 215 } 216 else 217 { 218 replaceFieldAccessInternally(clazz, field, false, true, fieldIndex); 219 method.setBody(code); 220 } 221 } 222 } 223 224 225 protected CtMethod getWrapperReadMethod(CtField field, CtClass clazz)throws NotFoundException 226 { 227 return clazz.getDeclaredMethod(fieldRead(field.getName())); 228 } 229 230 protected CtMethod getWrapperWriteMethod(CtField field, CtClass clazz)throws NotFoundException 231 { 232 return clazz.getDeclaredMethod(fieldWrite(field.getName())); 233 } 234 235 243 public void unwrap(CtClass clazz, Collection fieldsGet, Collection fieldsSet) throws CannotCompileException, NotFoundException 244 { 245 ClassPool classPool = instrumentor.getClassPool(); 246 List advisableFields = instrumentor.getAdvisableFields(clazz); 247 CtField[] fields = new CtField[advisableFields.size()]; 248 fields = (CtField[] ) advisableFields.toArray(fields); 249 for (Iterator iterator = fieldsGet.iterator(); iterator.hasNext(); ) 251 { 252 int fieldIndex = ((Integer ) iterator.next()).intValue(); 253 CtField field = fields[fieldIndex]; 254 if (wrapper.isNotPrepared(field, GET_INDEX)) 255 { 256 continue; 257 } 258 wrapper.unwrap(field, GET_INDEX); 260 CtMethod method = clazz.getDeclaredMethod(fieldRead(field.getName())); 262 String target = Modifier.isStatic(field.getModifiers())? clazz.getName(): "((" + clazz.getName() + ")$1)"; 263 method.setBody("return " + target + "." + field.getName() + ";"); 264 } 265 266 for (Iterator iterator = fieldsSet.iterator(); iterator.hasNext(); ) 267 { 268 int fieldIndex = ((Integer ) iterator.next()).intValue(); 269 CtField field = fields[fieldIndex]; 270 if (wrapper.isNotPrepared(field, SET_INDEX)) 271 { 272 continue; 273 } 274 wrapper.unwrap(field, SET_INDEX); 276 CtMethod method = clazz.getDeclaredMethod(fieldWrite(field.getName())); 279 String target = Modifier.isStatic(field.getModifiers())? clazz.getName(): "((" + clazz.getName() + ")$1)"; 280 method.setBody(target + "." + field.getName() + "=$2" + ";"); 281 } 282 } 283 284 287 public void codeConverted() throws NotFoundException, CannotCompileException { 288 codifier.codifyPending(); 289 } 290 291 protected int fieldOffset(CtClass clazz) throws NotFoundException 292 { 293 if (clazz == null) 294 return 0; 295 if (clazz.getName().equals("java.lang.Object")) 296 return 0; 297 int offset = fieldOffset(clazz.getSuperclass()); 298 299 CtField[] fields = clazz.getDeclaredFields(); 300 for (int i = 0; i < fields.length; i++) 301 { 302 if (Advisable.isAdvisable(fields[i])) 303 { 304 offset++; 305 } 306 } 307 return offset; 308 } 309 310 316 private JoinpointClassification[] classifyFieldGet(CtClass clazz, ClassAdvisor advisor) throws NotFoundException 317 { 318 List fields = instrumentor.getAdvisableFields(clazz); 319 JoinpointClassification[] classification = new JoinpointClassification[fields.size()]; 320 int index = 0; 321 for (Iterator iterator = fields.iterator(); iterator.hasNext(); index++) 322 { 323 CtField field = (CtField) iterator.next(); 324 classification[index] = instrumentor.joinpointClassifier.classifyFieldGet(field, advisor); 325 } 326 return classification; 327 } 328 329 335 private JoinpointClassification[] classifyFieldSet(CtClass clazz, ClassAdvisor advisor) throws NotFoundException 336 { 337 List fields = instrumentor.getAdvisableFields(clazz); 338 JoinpointClassification[] classification = new JoinpointClassification[fields.size()]; 339 int index = 0; 340 for (Iterator iterator = fields.iterator(); iterator.hasNext(); index++) 341 { 342 CtField field = (CtField) iterator.next(); 343 classification[index] = instrumentor.joinpointClassifier.classifyFieldSet(field, advisor); 344 } 345 return classification; 346 } 347 348 protected String addFieldReadInfoFieldWithAccessors(int modifiers, CtClass addTo, CtField field) throws NotFoundException, CannotCompileException 349 { 350 return addFieldReadInfoFieldWithAccessors(modifiers, addTo, field, null); 351 } 352 353 356 protected String addFieldReadInfoFieldWithAccessors(int modifiers, CtClass addTo, CtField field, CtField.Initializer init) throws NotFoundException, CannotCompileException 357 { 358 String name = getFieldReadInfoFieldName(field.getName()); 359 TransformerCommon.addInfoField(instrumentor, FIELD_INFO_CLASS_NAME, name, modifiers, addTo, addInfoAsWeakReference(), init); 360 return name; 361 } 362 363 protected String addFieldWriteInfoField(int modifiers, CtClass addTo, CtField field) throws NotFoundException, CannotCompileException 364 { 365 return addFieldWriteInfoField(modifiers, addTo, field, null); 366 } 367 368 371 protected String addFieldWriteInfoField(int modifiers, CtClass addTo, CtField field, CtField.Initializer init) throws NotFoundException, CannotCompileException 372 { 373 String name = getFieldWriteInfoFieldName(field.getName()); 374 TransformerCommon.addInfoField(instrumentor, FIELD_INFO_CLASS_NAME, name, modifiers, addTo, addInfoAsWeakReference(), init); 375 return name; 376 } 377 378 protected boolean addInfoAsWeakReference() 379 { 380 return true; 381 } 382 383 public static String getFieldReadInfoFieldName(String fieldName) 384 { 385 return "aop$FieldInfo_r_" + fieldName; 386 } 387 388 public static String getFieldWriteInfoFieldName(String fieldName) 389 { 390 return "aop$FieldInfo_w_" + fieldName; 391 } 392 393 public static String fieldRead(String fieldName) 394 { 395 return fieldName + "_r_" + ClassAdvisor.NOT_TRANSFORMABLE_SUFFIX; 396 } 397 398 public static String fieldWrite(String fieldName) 399 { 400 return fieldName + "_w_" + ClassAdvisor.NOT_TRANSFORMABLE_SUFFIX; 401 } 402 403 protected static String fieldInfoFromWeakReference(String localName, String fieldInfoName) 404 { 405 return TransformerCommon.infoFromWeakReference(FIELD_INFO_CLASS_NAME, localName, fieldInfoName); 406 } 407 408 protected int getStaticModifiers(CtField field) 409 { 410 int mod = Modifier.STATIC; 411 if ((field.getModifiers() & Modifier.PUBLIC) != 0) 412 { 413 mod |= Modifier.PUBLIC; 414 } 415 else if ((field.getModifiers() & Modifier.PROTECTED) != 0) 416 { 417 mod |= Modifier.PROTECTED; 418 } 419 else if ((field.getModifiers() & Modifier.PRIVATE) != 0) 420 { 421 mod |= Modifier.PRIVATE; 422 } 423 else 424 { 425 mod |= Modifier.PUBLIC; 426 } 427 428 return mod; 429 } 430 431 443 protected abstract void replaceFieldAccessInternally(CtClass clazz, CtField field, boolean doGet, boolean doSet, int index) throws CannotCompileException; 444 445 450 protected void buildWrapperPlaceHolders(CtClass clazz, CtField field, boolean doGet, boolean doSet, int mod) 451 throws NotFoundException, CannotCompileException 452 { 453 if (doGet) 454 { 455 buildReadWrapperPlaceHolder(clazz, field, fieldRead(field.getName()), mod); 456 } 457 if (doSet) 458 { 459 buildWriteWrapperPlaceHolder(clazz, field, fieldWrite(field.getName()), mod); 460 } 461 } 462 463 471 protected CtMethod buildReadWrapperPlaceHolder(CtClass clazz, CtField field, String wrapperName, int mod) 472 throws NotFoundException, CannotCompileException 473 { 474 AOPClassPool classPool = (AOPClassPool) instrumentor.getClassPool(); 475 476 String name = field.getName(); 477 CtClass ftype = field.getType(); 478 CtClass[] readParam = new CtClass[]{classPool.get("java.lang.Object")}; 479 480 String code = "{" + ftype.getName() + " var = "; 483 if (ftype.isPrimitive()) 484 { 485 if (ftype == CtClass.booleanType) 486 { 487 code += false; 488 } 489 else if (ftype == CtClass.byteType) 490 { 491 code += "(byte)0"; 492 } 493 else if (ftype == CtClass.charType) 494 { 495 code += "(char)0"; 496 } 497 else if (ftype == CtClass.doubleType) 498 { 499 code += "0.0"; 500 } 501 else if (ftype == CtClass.floatType) 502 { 503 code += "(float)0.0"; 504 } 505 else if (ftype == CtClass.intType) 506 { 507 code += "0"; 508 } 509 else if (ftype == CtClass.longType) 510 { 511 code += "(long)0"; 512 } 513 else if (ftype == CtClass.shortType) 514 { 515 code += "(short)0"; 516 } 517 } 518 else 519 { 520 code += "null"; 521 } 522 code += "; return var;}"; 523 CtMethod rmethod = CtNewMethod.make(ftype, wrapperName, readParam, null, code, clazz); 524 rmethod.setModifiers(mod); 525 clazz.addMethod(rmethod); 526 527 return rmethod; 528 } 529 530 538 protected CtMethod buildWriteWrapperPlaceHolder(CtClass clazz, CtField field, String wrapperName, int mod) 539 throws NotFoundException, CannotCompileException 540 { 541 AOPClassPool classPool = (AOPClassPool) instrumentor.getClassPool(); 542 543 String name = field.getName(); 544 CtClass ftype = field.getType(); 545 546 CtClass[] writeParam = new CtClass[2]; 548 writeParam[0] = classPool.get("java.lang.Object"); 549 writeParam[1] = ftype; 550 551 554 CtMethod wmethod = CtNewMethod.make(CtClass.voidType, wrapperName, writeParam, null, "{}", clazz); 555 wmethod.setModifiers(mod); 556 clazz.addMethod(wmethod); 557 558 return wmethod; 559 } 560 561 570 protected abstract String getWrapperBody(CtClass clazz, CtField field, boolean get, int fieldIndex) throws NotFoundException, CannotCompileException; 571 572 protected abstract class FieldAccessExprEditor extends ExprEditor 573 { 574 CtClass clazz; 575 CtField field; 576 boolean doGet; 577 boolean doSet; 578 int fieldIndex; 579 580 public FieldAccessExprEditor(CtClass clazz, CtField field, boolean doGet, boolean doSet, int index) 581 { 582 this.clazz = clazz; 583 this.field = field; 584 this.doGet = doGet; 585 this.doSet = doSet; 586 this.fieldIndex = index; 587 } 588 589 public void edit(FieldAccess fieldAccess) throws CannotCompileException 590 { 591 if (!fieldAccess.getClassName().equals(clazz.getName())) return; 592 if (!fieldAccess.getFieldName().equals(field.getName())) return; 593 if (calledByInvocationClass(fieldAccess))return; 594 595 if (fieldAccess.isReader() && doGet) 596 { 597 replaceRead(fieldAccess); 598 } 599 if (fieldAccess.isWriter() && doSet) 600 { 601 replaceWrite(fieldAccess); 602 } 603 } 604 605 private boolean calledByInvocationClass(FieldAccess fieldAccess) 606 { 607 try 608 { 609 return isInvocationClass(fieldAccess.where().getDeclaringClass()); 610 } 611 catch (RuntimeException e) 612 { 613 return true; 616 } 617 } 618 619 private boolean isInvocationClass(CtClass superClazz) 620 { 621 try 622 { 623 if (superClazz == null) 624 { 625 return false; 626 } 627 if (superClazz.getName().equals("java.lang.Object")) 628 { 629 return false; 630 } 631 if (superClazz.getName().equals("org.jboss.aop.joinpoint.Invocation")) 632 { 633 return true; 634 } 635 return (isInvocationClass(superClazz.getSuperclass())); 636 } 637 catch (NotFoundException e) 638 { 639 throw new RuntimeException (e.getMessage(), e); 640 } 641 } 642 643 protected abstract void replaceRead(FieldAccess fieldAccess) throws CannotCompileException; 644 protected abstract void replaceWrite(FieldAccess fieldAccess) throws CannotCompileException; 645 } 647 648 } 649 | Popular Tags |