1 23 24 25 package com.sun.jdo.api.persistence.enhancer.impl; 26 27 29 import java.util.Map ; 30 import java.util.HashMap ; 31 import java.util.Enumeration ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.ArrayList ; 35 36 import com.sun.jdo.api.persistence.enhancer.classfile.*; 37 38 import com.sun.jdo.api.persistence.enhancer.util.Support; 39 40 import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData; 42 43 44 78 79 84 final class ClassAction 85 extends Support 86 implements VMConstants { 87 88 89 98 99 100 private static final String AnnotatedAttribute = "com.sun.jdo.api.persistence.enhancer.annotated"; private static final short AnnotatedVersion = 1; 102 103 static private final String jdoGetStateManagerName 105 = "jdoGetStateManager"; static private final String jdoSetStateManagerName 107 = "jdoSetStateManager"; static private final String jdoGetFlagsName 109 = "jdoGetFlags"; static private final String jdoSetFlagsName 111 = "jdoSetFlags"; static private final String jdoMakeDirtyName 113 = "jdoMakeDirty"; static private final String jdoIsDirtyName 115 = "jdoIsDirty"; static private final String jdoIsTransactionalName 117 = "jdoIsTransactional"; static private final String jdoIsPersistentName 119 = "jdoIsPersistent"; static private final String jdoIsNewName 121 = "jdoIsNew"; static private final String jdoIsDeletedName 123 = "jdoIsDeleted"; static private final String jdoGetPersistenceManagerName 125 = "jdoGetPersistenceManager"; static private final String jdoGetObjectIdName 127 = "jdoGetObjectId"; static private final String jdoConstructorName 129 = "<init>"; static private final String jdoNewInstanceName 131 = "jdoNewInstance"; static private final String jdoClearName 133 = "jdoClear"; static private final String jdoCopyName 135 = "jdoCopy"; static private final String jdoGetFieldName 137 = "jdoGetField"; static private final String jdoSetFieldName 139 = "jdoSetField"; static private final String jdoCloneName 141 = "clone"; 143 144 private final ClassControl control; 146 147 148 private final Environment env; 151 152 153 private final MethodBuilder methodBuilder; 156 157 158 private final Map methodActionTable = new HashMap (11); 161 162 163 private final List fieldActionTable = new ArrayList (); 166 167 169 173 174 175 private boolean previouslyAnnotated = false; 176 177 179 private boolean implementsPersistence = false; 180 181 183 188 189 190 private boolean sawImplementsPersistenceCapable = false; 192 private boolean sawImplementsCloneable = false; 193 private boolean sawFieldJDOStateManager = false; 194 private boolean sawFieldJDOFlags = false; 195 private boolean sawMethodJDOGetStateManager = false; 196 private boolean sawMethodJDOSetStateManager = false; 197 private boolean sawMethodJDOGetFlags = false; 198 private boolean sawMethodJDOSetFlags = false; 199 private boolean sawMethodJDOMakeDirty = false; 200 private boolean sawMethodJDOIsDirty = false; 201 private boolean sawMethodJDOIsTransactional = false; 202 private boolean sawMethodJDOIsPersistent = false; 203 private boolean sawMethodJDOIsNew = false; 204 private boolean sawMethodJDOIsDeleted = false; 205 private boolean sawMethodJDOGetPersistenceManager = false; 206 private boolean sawMethodJDOGetObjectId = false; 207 private boolean sawMethodJDOConstructor = false; 208 private boolean sawMethodJDONewInstance = false; 209 private boolean sawMethodJDOGetField = false; 210 private boolean sawMethodJDOSetField = false; 211 private boolean sawMethodJDOClear = false; 212 private boolean sawMethodJDOCopy = false; 213 private boolean sawMethodJDOClone = false; 214 215 217 221 222 224 228 229 231 235 236 238 242 243 244 246 249 public ClassAction(ClassControl control, 251 Environment env) { 252 this.control = control; 253 this.env = env; 254 this.methodBuilder = new MethodBuilder(env); 255 } 256 257 262 public void scan1() { 264 env.message("scanning class " + control.userClassName()); 267 affirm(!classFile().isInterface()); 269 affirm(control.persistType() > ClassControl.TransientOnly); 270 271 scanAttributes(); 272 273 if (previouslyAnnotated) { 275 return; 276 } 277 278 final String name = className(); 280 implementsPersistence 281 = env.getJDOMetaData().isPersistenceCapableRootClass(name); 282 283 final boolean isPersistent 285 = (control.persistType() == ClassControl.PersistCapable); 286 if (isPersistent) { 287 scanForImplementsInterfaces(); 290 291 scanFields(); 293 } 294 295 scanMethods(); 298 } 299 300 304 public void augment() { 307 if (previouslyAnnotated) 308 return; 309 310 if (implementsPersistence) { 311 env.message("augmenting class " + control.userClassName()); 313 if (!sawImplementsPersistenceCapable) { 314 augmentClassInterface(JDOMetaData.JDOPersistenceCapablePath); 315 } 316 317 if (!sawImplementsCloneable) { 318 augmentClassInterface(JDOMetaData.javaLangCloneablePath); 319 } 320 321 { 323 insertPersistenceCapableFields( 324 JDOMetaData.JDOStateManagerFieldName, 325 JDOMetaData.JDOStateManagerFieldSig, 326 JDOMetaData.JDOStateManagerFieldType, 327 ACCTransient | ACCPublic); 328 329 insertPersistenceCapableFields( 330 JDOMetaData.JDOFlagsFieldName, 331 JDOMetaData.JDOFlagsFieldSig, 332 JDOMetaData.JDOFlagsFieldType, 333 ACCTransient | ACCPublic); 334 } 335 336 insertPersistenceCapableMethods(); 337 } 338 339 352 } 353 354 358 434 435 438 public void annotate() { 439 if (previouslyAnnotated) 440 return; 441 442 env.message("annotating class " + control.userClassName()); 445 boolean updates = false; 446 447 for (Iterator e = methodActions(); e.hasNext(); ) { 448 MethodAction methodAction = (MethodAction)e.next(); 449 if (methodAction.needsAnnotation()) { 450 methodAction.annotate(); 451 updates = true; 452 } 453 } 454 455 472 473 if (updates || env.updateInPlace()) { 477 control.noteUpdate(); 478 479 481 final byte[] data = new byte[2]; 483 data[0] = (byte)(AnnotatedVersion >>> 8); 484 data[1] = (byte)(AnnotatedVersion & 0xff); 485 final ClassAttribute annotatedAttr 486 = new GenericAttribute( 487 classFile().pool().addUtf8(AnnotatedAttribute), data); 488 classFile().attributes().addElement(annotatedAttr); 489 } 490 } 491 492 494 497 ClassControl classControl() { 498 return control; 499 } 500 501 504 ClassFile classFile() { 505 return control.classFile(); 506 } 507 508 511 Iterator fieldActions() { 512 return fieldActionTable.iterator(); 513 } 514 515 518 Iterator methodActions() { 519 return methodActionTable.values().iterator(); 520 } 521 522 525 public String className() { 526 return control.className(); 527 } 528 529 532 public String userClassName() { 533 return control.userClassName(); 534 } 535 536 539 public boolean getImplementsPersistence() { 540 return implementsPersistence; 541 } 542 543 546 560 561 564 public boolean hasCloneMethod() { 565 return sawMethodJDOClone; 566 } 567 568 572 public boolean hasAnnotatedAttribute() { 573 if (previouslyAnnotated) 574 return true; 575 576 Enumeration e = classFile().attributes().elements(); 577 while (e.hasMoreElements()) { 578 ClassAttribute attr = (ClassAttribute) e.nextElement(); 579 if (attr.attrName().asString().equals(AnnotatedAttribute)) 580 return true; 581 } 582 583 return false; 584 } 585 586 591 605 606 608 611 private void scanAttributes() { 612 Enumeration e = classFile().attributes().elements(); 613 while (e.hasMoreElements()) { 614 ClassAttribute attr = (ClassAttribute) e.nextElement(); 615 if (attr.attrName().asString().equals(AnnotatedAttribute)) { 616 previouslyAnnotated = true; 617 618 622 { 623 env.message("ignoring previously enhanced class " + control.userClassName()); 627 } 628 break; 629 } 630 } 631 } 632 633 645 private void scanForImplementsInterfaces() { 647 for (Iterator ifc = classFile().interfaces().iterator(); 648 ifc.hasNext();) { 649 final ConstClass i = (ConstClass)ifc.next(); 650 String interfaceNamePath = i.asString(); 651 if (interfaceNamePath.equals(JDOMetaData.JDOPersistenceCapablePath)) { 652 sawImplementsPersistenceCapable = true; 653 654 env.warning( 656 getI18N("enhancer.class_implements_jdo_pc", new Object []{ 658 userClassName(), 659 JDOMetaData.JDOPersistenceCapableType 660 })); 661 } 662 if(JDOMetaData.javaLangCloneablePath.equals(interfaceNamePath) ) { 663 sawImplementsCloneable = true; 664 } 665 } 666 667 676 } 677 678 682 private void scanFields() { 683 Enumeration e = classFile().fields().elements(); 684 while (e.hasMoreElements()) { 685 final ClassField f = (ClassField)e.nextElement(); 686 final String fieldName = f.name().asString(); 687 final String fieldSig = f.signature().asString(); 688 689 scanForJDOFields(fieldName, fieldSig); 691 692 FieldAction action = new FieldAction(this, f, env); 693 action.check(); 694 fieldActionTable.add(action); 695 } 696 } 697 698 701 private void scanForJDOFields(String fieldName, 703 String fieldSig) { 704 if (fieldName.equals(JDOMetaData.JDOStateManagerFieldName)) { 705 env.error( 706 getI18N("enhancer.class_defines_jdo_field", userClassName(), 708 JDOMetaData.JDOStateManagerFieldName)); 709 sawFieldJDOStateManager = true; 710 return; 711 } 712 if (fieldName.equals(JDOMetaData.JDOFlagsFieldName)) { 713 env.error( 714 getI18N("enhancer.class_defines_jdo_field", userClassName(), 716 JDOMetaData.JDOFlagsFieldName)); 717 sawFieldJDOFlags = true; 718 return; 719 } 720 if (fieldName.startsWith("jdo")) { env.warning( 724 getI18N("enhancer.class_has_jdo_like_member", userClassName(), fieldName)); 726 return; 727 } 728 } 729 730 733 private void scanMethods() { 734 final boolean isPersistent 735 = (control.persistType() == ClassControl.PersistCapable); 736 737 Enumeration e = classFile().methods().elements(); 738 while (e.hasMoreElements()) { 739 final ClassMethod m = (ClassMethod)e.nextElement(); 740 final String methodName = m.name().asString(); 741 final String methodSig = m.signature().asString(); 742 743 if (isPersistent) { 744 scanForJDOMethods(methodName, methodSig); 745 } 746 747 final MethodAction action = new MethodAction(this, m, env); 748 action.check(); 749 methodActionTable.put(m, action); 750 } 751 } 752 753 754 757 private void scanForJDOMethods(String methodName, 759 String methodSig) { 760 if (methodName.equals(jdoGetStateManagerName)) { 761 env.error( 762 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 764 sawMethodJDOGetStateManager = true; 765 return; 766 } 767 if (methodName.equals(jdoSetStateManagerName)) { 768 env.error( 769 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 771 sawMethodJDOSetStateManager = true; 772 return; 773 } 774 if (methodName.equals(jdoGetFlagsName)) { 775 env.error( 776 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 778 sawMethodJDOGetFlags = true; 779 return; 780 } 781 if (methodName.equals(jdoSetFlagsName)) { 782 env.error( 783 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 785 sawMethodJDOSetFlags = true; 786 return; 787 } 788 if (methodName.equals(jdoMakeDirtyName)) { 789 env.error( 790 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 792 sawMethodJDOMakeDirty = true; 793 return; 794 } 795 if (methodName.equals(jdoIsDirtyName)) { 796 env.error( 797 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 799 sawMethodJDOIsDirty = true; 800 return; 801 } 802 if (methodName.equals(jdoIsTransactionalName)) { 803 env.error( 804 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 806 sawMethodJDOIsTransactional = true; 807 return; 808 } 809 if (methodName.equals(jdoIsPersistentName)) { 810 env.error( 811 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 813 sawMethodJDOIsPersistent = true; 814 return; 815 } 816 if (methodName.equals(jdoIsNewName)) { 817 env.error( 818 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 820 sawMethodJDOIsNew = true; 821 return; 822 } 823 if (methodName.equals(jdoIsDeletedName)) { 824 env.error( 825 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 827 sawMethodJDOIsDeleted = true; 828 return; 829 } 830 if (methodName.equals(jdoGetPersistenceManagerName)) { 831 env.error( 832 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 834 sawMethodJDOGetPersistenceManager = true; 835 return; 836 } 837 if (methodName.equals(jdoGetObjectIdName)) { 838 env.error( 839 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 841 sawMethodJDOGetObjectId = true; 842 return; 843 } 844 if (methodName.equals(jdoConstructorName) 847 && methodSig.equals("(" + JDOMetaData.JDOStateManagerSig + ")V")) { env.error( 849 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 851 sawMethodJDOConstructor = true; 852 return; 853 } 854 if (methodName.equals(jdoNewInstanceName)) { 855 env.error( 856 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 858 sawMethodJDONewInstance = true; 859 return; 860 } 861 if (methodName.equals(jdoClearName)) { 862 env.error( 863 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 865 sawMethodJDOClear = true; 866 return; 867 } 868 if (methodName.equals(jdoCopyName)) { 869 env.error( 870 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 872 sawMethodJDOCopy = true; 873 return; 874 } 875 if (methodName.equals(jdoGetFieldName)) { 876 env.error( 877 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 879 sawMethodJDOGetField = true; 880 return; 881 } 882 if (methodName.equals(jdoSetFieldName)) { 883 env.error( 884 getI18N("enhancer.class_defines_jdo_method", userClassName(), methodName)); 886 sawMethodJDOSetField = true; 887 return; 888 } 889 if (methodName.equals(jdoCloneName) 892 && methodSig.equals("()Ljava/lang/Object;")) { sawMethodJDOClone = true; 895 return; 896 } 897 if (methodName.startsWith("jdo")) { env.warning( 901 getI18N("enhancer.class_has_jdo_like_member", userClassName(), methodName)); 903 return; 904 } 905 906 912 924 939 948 } 949 950 953 private void insertPersistenceCapableFields(String fieldName, 954 String fieldSig, 955 String printableFieldSig, 956 int accessFlags) { 957 affirm(implementsPersistence); 958 959 control.noteUpdate(); 960 961 env.message("adding " + control.userClassName() + 964 "." + fieldName + " " + printableFieldSig); 966 final ClassFile cfile = classFile(); 967 final ConstantPool pool = cfile.pool(); 968 969 final AttributeVector fieldAttrs = new AttributeVector(); 971 fieldAttrs.addElement( 972 new SyntheticAttribute( 973 pool.addUtf8(SyntheticAttribute.expectedAttrName))); 974 975 final ClassField theField 976 = new ClassField(accessFlags, 977 pool.addUtf8(fieldName), 978 pool.addUtf8(fieldSig), 979 fieldAttrs); 980 981 cfile.addField(theField); 982 } 983 984 987 private void insertPersistenceCapableMethods() { 988 affirm(implementsPersistence); 989 990 control.noteUpdate(); 991 992 affirm(!sawMethodJDOGetStateManager); 994 classFile().addMethod( 995 methodBuilder.makeJDOGetStateManager( 996 this, 997 jdoGetStateManagerName)); 998 999 affirm(!sawMethodJDOSetStateManager); 1000 classFile().addMethod( 1001 methodBuilder.makeJDOSetStateManager( 1002 this, 1003 jdoSetStateManagerName)); 1004 1005 affirm(!sawMethodJDOGetFlags); 1007 classFile().addMethod( 1008 methodBuilder.makeJDOGetFlags( 1009 this, 1010 jdoGetFlagsName)); 1011 affirm(!sawMethodJDOSetFlags); 1012 classFile().addMethod( 1013 methodBuilder.makeJDOSetFlags( 1014 this, 1015 jdoSetFlagsName)); 1016 1017 affirm(!sawMethodJDOMakeDirty); 1019 classFile().addMethod( 1020 methodBuilder.makeJDOMakeDirtyMethod( 1021 this, 1022 jdoMakeDirtyName)); 1023 1024 affirm(!sawMethodJDOIsDirty); 1026 classFile().addMethod( 1027 methodBuilder.makeJDOInterrogativeMethod( 1028 this, 1029 jdoIsDirtyName)); 1030 affirm(!sawMethodJDOIsTransactional); 1031 classFile().addMethod( 1032 methodBuilder.makeJDOInterrogativeMethod( 1033 this, 1034 jdoIsTransactionalName)); 1035 affirm(!sawMethodJDOIsPersistent); 1036 classFile().addMethod( 1037 methodBuilder.makeJDOInterrogativeMethod( 1038 this, 1039 jdoIsPersistentName)); 1040 affirm(!sawMethodJDOIsNew); 1041 classFile().addMethod( 1042 methodBuilder.makeJDOInterrogativeMethod( 1043 this, 1044 jdoIsNewName)); 1045 affirm(!sawMethodJDOIsDeleted); 1046 classFile().addMethod( 1047 methodBuilder.makeJDOInterrogativeMethod( 1048 this, 1049 jdoIsDeletedName)); 1050 1051 affirm(!sawMethodJDOGetPersistenceManager); 1053 classFile().addMethod( 1054 methodBuilder.makeJDOGetPersistenceManagerMethod( 1055 this, 1056 jdoGetPersistenceManagerName)); 1057 1058 affirm(!sawMethodJDOGetObjectId); 1060 classFile().addMethod( 1061 methodBuilder.makeJDOGetObjectIdMethod( 1062 this, 1063 jdoGetObjectIdName)); 1064 1065 affirm(!sawMethodJDOConstructor); 1067 classFile().addMethod( 1068 methodBuilder.makeJDOConstructor( 1069 this, 1070 jdoConstructorName)); 1071 1072 affirm(!sawMethodJDONewInstance); 1074 classFile().addMethod( 1075 methodBuilder.makeJDONewInstanceMethod( 1076 this, 1077 jdoNewInstanceName)); 1078 1079 affirm(!sawMethodJDOGetField); 1081 classFile().addMethod( 1082 methodBuilder.makeJDOGetFieldMethod( 1083 this, 1084 jdoGetFieldName)); 1085 1086 affirm(!sawMethodJDOSetField); 1088 classFile().addMethod( 1089 methodBuilder.makeJDOSetFieldMethod( 1090 this, 1091 jdoSetFieldName)); 1092 1093 affirm(!sawMethodJDOClear); 1095 classFile().addMethod( 1096 methodBuilder.makeJDOClearMethod( 1097 this, 1098 jdoClearName)); 1099 1100 1109 1110 if (!sawMethodJDOClone) { 1112 classFile().addMethod( 1113 methodBuilder.makeJDOClone( 1114 this, 1115 jdoCloneName)); 1116 } 1117 } 1118 1119 1122 1146 1147 1150 private void augmentClassInterface(String interfaceName) { 1151 control.noteUpdate(); 1152 ClassFile cfile = classFile(); 1153 ConstClass iface = cfile.pool().addClass(interfaceName); 1154 env.message("adding implements " + ClassControl.userClassFromVMClass(interfaceName)); 1157 cfile.addInterface(iface); 1158 } 1159} 1160 | Popular Tags |