1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.impl.enhancer.core;
19
20 import java.util.Collection;
21 import java.util.Enumeration;
22 import java.util.Iterator;
23 import java.util.Arrays;
24 import java.util.Set;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.HashMap;
28
29 import org.apache.jdo.impl.enhancer.classfile.ClassAttribute;
30 import org.apache.jdo.impl.enhancer.classfile.ClassField;
31 import org.apache.jdo.impl.enhancer.classfile.ClassFile;
32 import org.apache.jdo.impl.enhancer.classfile.ClassMethod;
33 import org.apache.jdo.impl.enhancer.classfile.ConstClass;
34 import org.apache.jdo.impl.enhancer.classfile.ConstantPool;
35 import org.apache.jdo.impl.enhancer.classfile.GenericAttribute;
36 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
37 import org.apache.jdo.impl.enhancer.util.Support;
38
39
40
41
42
43 /***
44 * Analyzes a class for enhancement.
45 */
46 final class Analyzer
47 extends Support
48 implements JDOConstants, EnhancerConstants
49 {
50 /***
51 * The class is not to be modified by the enahncer.
52 */
53 static public final int CC_Unenhancable = -2;
54
55 /***
56 * The class is detected to be enhanced already and is not to be modifed.
57 */
58 static public final int CC_PreviouslyEnhanced = -1;
59
60 /***
61 * The enhancement status of the class hasn't been determined yet.
62 */
63 static public final int CC_PersistenceUnknown = 0;
64
65 /***
66 * The class is to be enhanced for persistence-awareness.
67 */
68 static public final int CC_PersistenceAware = 1;
69
70 /***
71 * The class is to be enhanced for specific persistence-capability
72 * (class does extend another persistence-capable class).
73 */
74 static public final int CC_PersistenceCapable = 2;
75
76 /***
77 * The class is to be enhanced for generic and specific
78 * persistence-capability (class does not extend another
79 * persistence-capable class).
80 */
81 static public final int CC_PersistenceCapableRoot = 3;
82
83 /***
84 * The names of the jdo fields of persistene-capable classes.
85 */
86 static private final Set jdoFieldNames = new HashSet();
87 static
88 {
89 jdoFieldNames.add(JDO_PC_jdoStateManager_Name);
90 jdoFieldNames.add(JDO_PC_jdoFlags_Name);
91 jdoFieldNames.add(JDO_PC_jdoInheritedFieldCount_Name);
92 jdoFieldNames.add(JDO_PC_jdoFieldNames_Name);
93 jdoFieldNames.add(JDO_PC_jdoFieldTypes_Name);
94 jdoFieldNames.add(JDO_PC_jdoFieldFlags_Name);
95 jdoFieldNames.add(JDO_PC_jdoPersistenceCapableSuperclass_Name);
96 }
97
98 /***
99 * The classfile's enhancement controller.
100 */
101 private final Controller control;
102
103 /***
104 * The classfile to be enhanced.
105 */
106 private final ClassFile classFile;
107
108 /***
109 * The class name in VM form.
110 */
111 private final String className;
112
113 /***
114 * The class name in user ('.' delimited) form.
115 */
116 private final String userClassName;
117
118 /***
119 * The classfile's constant pool.
120 */
121 private final ConstantPool pool;
122
123 /***
124 * Repository for the enhancement options.
125 */
126 private final Environment env;
127
128 /***
129 * Repository for JDO meta-data on classes.
130 */
131 private final EnhancerMetaData meta;
132
133 /***
134 * What type of class is this with respect to persistence.
135 */
136 private int persistenceType = CC_PersistenceUnknown;
137
138 /***
139 * The name of the persistence-capable superclass if defined.
140 */
141 private String pcSuperClassName;
142
143 /***
144 * The name of the persistence-capable rootclass if defined.
145 */
146 private String pcRootClassName;
147
148 /***
149 * The name of this class or the next persistence-capable superclass
150 * that owns a key class, or the PC rootclass if none defines a key class.
151 */
152 private String pcKeyOwnerClassName;
153
154 /***
155 * The name next persistence-capable superclass that owns a key class,
156 * or the PC rootclass if none defines a key class.
157 */
158 private String pcSuperKeyOwnerClassName;
159
160 /***
161 * The name of the key class if defined.
162 */
163 private String keyClassName;
164
165 /***
166 * The name of the key class of the next persistence-capable superclass
167 * that defines one.
168 */
169 private String superKeyClassName;
170
171 /***
172 * The number of key fields.
173 */
174 private int keyFieldCount;
175
176 /***
177 * The indexes of all key fields.
178 */
179 private int[] keyFieldIndexes;
180
181 /***
182 * The number of managed fields.
183 */
184 private int managedFieldCount;
185
186 /***
187 * The number of annotated fields.
188 */
189 private int annotatedFieldCount;
190
191 /***
192 * The names of all annotated fields sorted by relative field index.
193 */
194 private String[] annotatedFieldNames;
195
196 /***
197 * The type names of all annotated fields sorted by relative field index.
198 */
199 private String[] annotatedFieldSigs;
200
201 /***
202 * The java access modifiers of all annotated fields sorted by relative
203 * field index.
204 */
205 private int[] annotatedFieldMods;
206
207 /***
208 * The jdo flags of all annotated fields sorted by relative field index.
209 */
210 private int[] annotatedFieldFlags;
211
212 /***
213 * The map of found JDO fields.
214 */
215 private final Map jdoLikeFields = new HashMap(20);
216
217 /***
218 * The map of found JDO methods
219 */
220 private final Map jdoLikeMethods = new HashMap(50);
221
222 /***
223 * The map of found JDO methods
224 */
225 private final Map annotatableMethods = new HashMap(100);
226
227 /***
228 * True if a jdo member has been seen in this class.
229 */
230 private boolean hasImplementsPC = false;
231 private boolean hasGenericJDOFields = false;
232 private boolean hasGenericJDOMethods = false;
233 private boolean hasGenericJDOMembers = false;
234 private boolean hasSpecificJDOFields = false;
235 private boolean hasSpecificJDOMethods = false;
236 private boolean hasSpecificJDOMembers = false;
237 private boolean hasCallbackJDOMethods = false;
238 private boolean hasJDOMembers = false;
239
240 /***
241 * True if the class has a default (no-argument) constructor.
242 */
243 private boolean hasDefaultConstructor = false;
244
245
246
247 /***
248 * True if the class has a static initializer block.
249 */
250 private boolean hasStaticInitializer = false;
251
252 /***
253 * True if the class has a clone() method.
254 */
255 private boolean hasCloneMethod = false;
256
257 /***
258 * True if the class has a writeObject(java.io.ObjectOutputStream) method.
259 */
260 private boolean hasWriteObjectMethod = false;
261
262 /***
263 * True if the class has a writeReplace() method.
264 */
265 private boolean hasWriteReplaceMethod = false;
266
267 /***
268 * True if the class has a readObject(java.io.ObjectInputStream) method.
269 */
270 private boolean hasReadObjectMethod = false;
271
272
273
274 /***
275 * Constructor
276 */
277 public Analyzer(Controller control,
278 Environment env)
279 {
280 affirm(control != null);
281 affirm(env != null);
282
283 this.control = control;
284 this.classFile = control.getClassFile();
285 this.className = classFile.classNameString();
286 this.userClassName = classFile.userClassName();
287 this.pool = classFile.pool();
288 this.env = env;
289 this.meta = env.getEnhancerMetaData();
290
291 affirm(classFile != null);
292 affirm(className != null);
293 affirm(userClassName != null);
294 affirm(pool != null);
295 affirm(meta != null);
296 }
297
298 /***
299 * Returns the class file which we are operating on.
300 */
301 public ClassFile getClassFile()
302 {
303 return classFile;
304 }
305
306 /***
307 * Return the persistence type for this class
308 */
309 public int getPersistenceType()
310 {
311 return persistenceType;
312 }
313
314 /***
315 * Returns true if the class has been analyzed already.
316 */
317 public boolean isAnalyzed()
318 {
319 return (persistenceType != CC_PersistenceUnknown);
320 }
321
322 /***
323 * Returns true if the class is one which should be a candidate for
324 * annotation.
325 */
326 public boolean isAnnotateable()
327 {
328 return (persistenceType >= CC_PersistenceUnknown);
329 }
330
331 /***
332 * Returns true if the class is to be enhanced for persistence-capability.
333 */
334 public boolean isAugmentable()
335 {
336 return (persistenceType >= CC_PersistenceCapable);
337 }
338
339 /***
340 * Returns true if the class is to be enhanced as least-derived,
341 * persistence-capable class.
342 */
343 public boolean isAugmentableAsRoot()
344 {
345 return (persistenceType >= CC_PersistenceCapableRoot);
346 }
347
348 /***
349 * Returns the methods that are candidates for annotation.
350 */
351 public Collection getAnnotatableMethods()
352 {
353 return annotatableMethods.values();
354 }
355
356 /***
357 * Returns the name of the persistence-capable superclass if defined.
358 */
359 public String getPCSuperClassName()
360 {
361 return pcSuperClassName;
362 }
363
364 /***
365 * Returns the name of the persistence-capable rootclass if defined.
366 */
367 public String getPCRootClassName()
368 {
369 return pcRootClassName;
370 }
371
372 /***
373 * Returns the name of this class or the next persistence-capable
374 * superclass that owns a key class.
375 */
376 public String getPCKeyOwnerClassName()
377 {
378 return pcKeyOwnerClassName;
379 }
380
381 /***
382 * Returns the name of this class or the next persistence-capable
383 * that owns a key class.
384 */
385 public String getPCSuperKeyOwnerClassName()
386 {
387 return pcSuperKeyOwnerClassName;
388 }
389
390 /***
391 * Returns the name of the key class if defined.
392 */
393 public String getKeyClassName()
394 {
395 return keyClassName;
396 }
397
398 /***
399 * Returns the name of the key class of the next persistence-capable
400 * superclass that defines one.
401 */
402 public String getSuperKeyClassName()
403 {
404 return superKeyClassName;
405 }
406
407 /***
408 * Returns the number of key field.
409 */
410 public int getKeyFieldCount()
411 {
412 return keyFieldCount;
413 }
414
415 /***
416 * Returns the names of the key fields.
417 */
418 public int[] getKeyFieldIndexes()
419 {
420 return keyFieldIndexes;
421 }
422
423 /***
424 * Returns the number of managed field.
425 */
426 public int getManagedFieldCount()
427 {
428 return managedFieldCount;
429 }
430
431 /***
432 * Returns the number of annotated field.
433 */
434 public int getAnnotatedFieldCount()
435 {
436 return annotatedFieldCount;
437 }
438
439 /***
440 * Returns the names of the annotated fields.
441 */
442 public String[] getAnnotatedFieldNames()
443 {
444 return annotatedFieldNames;
445 }
446
447 /***
448 * Returns the types names of the annotated fields.
449 */
450 public String[] getAnnotatedFieldSigs()
451 {
452 return annotatedFieldSigs;
453 }
454
455 /***
456 * Returns the Java access modifiers of the annotated fields.
457 */
458 public int[] getAnnotatedFieldMods()
459 {
460 return annotatedFieldMods;
461 }
462
463 /***
464 * Returns the JDO flags of the annotated fields.
465 */
466 public int[] getAnnotatedFieldFlags()
467 {
468 return annotatedFieldFlags;
469 }
470
471 /***
472 * Returns true if the class has a default (no-argument) constructor.
473 */
474 public boolean hasDefaultConstructor()
475 {
476 return hasDefaultConstructor;
477 }
478
479 /***
480 * Returns true if the class has a static initializer block.
481 */
482 public boolean hasStaticInitializer()
483 {
484 return hasStaticInitializer;
485 }
486
487 /***
488 * Returns true if the class has a clone() method.
489 */
490 public boolean hasCloneMethod()
491 {
492 return hasCloneMethod;
493 }
494
495 /***
496 * Returns true if the class has a writeObject() method.
497 */
498 public boolean hasWriteObjectMethod()
499 {
500 return hasWriteObjectMethod;
501 }
502
503 /***
504 * Returns true if the class has a writeReplace() method.
505 */
506 public boolean hasWriteReplaceMethod()
507 {
508 return hasWriteReplaceMethod;
509 }
510
511 /***
512 * Returns true if the class has a readObject() method.
513 */
514 public boolean hasReadObjectMethod()
515 {
516 return hasReadObjectMethod;
517 }
518
519 /***
520 * Returns true if the class already provides the JDO augmentation.
521 */
522 public boolean hasJDOAugmentation()
523 {
524 return hasJDOMembers;
525 }
526
527
528
529 /***
530 * Analyzes the class for existing augmentation.
531 */
532 public void scan()
533 {
534 env.message("scanning class " + userClassName);
535
536
537 checkForEnhancedAttribute();
538 if (!isAnnotateable()) {
539 return;
540 }
541
542
543 initPersistenceType();
544 if (!isAnnotateable()) {
545 return;
546 }
547 affirm(persistenceType > CC_Unenhancable);
548
549 scanFields();
550 scanMethods();
551
552 if (isAugmentable()) {
553 checkPCFeasibility();
554 checkSpecificAugmentation();
555 checkCallbackAugmentation();
556
557 if (isAugmentableAsRoot()) {
558 checkGenericAugmentation();
559 }
560 }
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581 }
582
583 /***
584 * Scans the attributes of a ClassFile
585 */
586 private void checkForEnhancedAttribute()
587 {
588 for (Enumeration e = classFile.attributes().elements();
589 e.hasMoreElements();) {
590 final ClassAttribute attr = (ClassAttribute)e.nextElement();
591 final String attrName = attr.attrName().asString();
592 if (SUNJDO_PC_EnhancedAttribute.equals(attrName)) {
593 persistenceType = CC_PreviouslyEnhanced;
594
595
596
597 env.message("ignoring previously enhanced class "
598 + userClassName);
599 return;
600 }
601 }
602 }
603
604
605
606 /***
607 * Sets the persistence type of a class according to JDO metadata.
608 */
609 private void initPersistenceType()
610 {
611 affirm(persistenceType == CC_PersistenceUnknown);
612
613
614 final EnhancerMetaData meta = env.getEnhancerMetaData();
615 if (meta.isKnownUnenhancableClass(className)) {
616 persistenceType = CC_Unenhancable;
617 return;
618 }
619
620
621 if (meta.isPersistenceCapableClass(className)) {
622 pcSuperClassName
623 = meta.getPersistenceCapableSuperClass(className);
624 pcRootClassName
625 = meta.getPersistenceCapableRootClass(className);
626 affirm(pcSuperClassName == null || pcRootClassName != null);
627
628 persistenceType
629 = (pcSuperClassName == null
630 ? CC_PersistenceCapableRoot
631 : CC_PersistenceCapable);
632
633
634 affirm(!classFile.isInterface());
635
636
637
638
639 final ConstClass superConstClass = classFile.superName();
640 affirm(superConstClass != null);
641
642
643 affirm(pcSuperClassName == null
644 || !superConstClass.asString().equals("java/lang/Object"));
645
646
647 pcKeyOwnerClassName = className;
648 while (meta.getKeyClass(pcKeyOwnerClassName) == null) {
649 final String pcSuperClassName
650 = meta.getPersistenceCapableSuperClass(
651 pcKeyOwnerClassName);
652 if (pcSuperClassName == null)
653 break;
654 pcKeyOwnerClassName = pcSuperClassName;
655 }
656 affirm(pcKeyOwnerClassName != null);
657
658
659 pcSuperKeyOwnerClassName = pcSuperClassName;
660 if (pcSuperKeyOwnerClassName != null) {
661 while (meta.getKeyClass(pcSuperKeyOwnerClassName) == null) {
662 final String pcSuperClassName
663 = meta.getPersistenceCapableSuperClass(
664 pcSuperKeyOwnerClassName);
665 if (pcSuperClassName == null)
666 break;
667 pcSuperKeyOwnerClassName = pcSuperClassName;
668 }
669 affirm(pcKeyOwnerClassName != null);
670 }
671
672 keyClassName
673 = meta.getKeyClass(className);
674 superKeyClassName
675 = meta.getSuperKeyClass(className);
676 affirm(superKeyClassName == null || pcSuperClassName != null);
677 }
678 }
679
680 /***
681 * Scans the fields.
682 */
683 private void scanFields()
684 {
685
686 final Map annotatedFieldMap = new HashMap();
687
688 if (isAugmentable()) {
689
690 for (final Enumeration e = classFile.fields().elements();
691 e.hasMoreElements();) {
692 final ClassField field = (ClassField)e.nextElement();
693 final String name = field.name().asString();
694 final String sig = field.signature().asString();
695
696
697 if (jdoFieldNames.contains(name)) {
698 continue;
699 }
700
701
702 if (field.isStatic()) {
703 continue;
704 }
705
706
707 if (meta.isKnownNonManagedField(className, name, sig)) {
708 continue;
709 }
710
711
712 Object obj = annotatedFieldMap.put(name, field);
713 affirm(obj == null,
714 ("Error in classfile: repeated declaration of field: "
715 + userClassName + "." + name));
716
717
718 if (field.isFinal()
719 || field.isTransient()) {
720 continue;
721 }
722
723 if (false) {
724 System.out.println("Analyzer.scanFields(): declaring "
725 + className + "." + name + " : " + sig);
726 }
727 meta.declareField(className, name, sig);
728 }
729 }
730
731
732 annotatedFieldCount = annotatedFieldMap.size();
733
734
735 final String[] managedFieldNames = meta.getManagedFields(className);
736 affirm(managedFieldNames != null);
737 managedFieldCount = managedFieldNames.length;
738 final Set managedFieldNamesSet
739 = new HashSet(Arrays.asList(managedFieldNames));
740 affirm(managedFieldNamesSet.size() == managedFieldCount,
741 "JDO metadata: returned duplicate managed fields.");
742 affirm(managedFieldCount <= annotatedFieldCount,
743 "JDO metadata: managed fields exceed annotated fields.");
744
745
746 final String[] keyFieldNames = meta.getKeyFields(className);
747 affirm(keyFieldNames != null);
748 keyFieldCount = keyFieldNames.length;
749 affirm(keyFieldCount == 0 || keyClassName != null,
750 "JDO metadata: returned key fields but no key class.");
751 final Set keyFieldNamesSet
752 = new HashSet(Arrays.asList(keyFieldNames));
753 affirm(keyFieldNamesSet.size() == keyFieldCount,
754 "JDO metadata: returned duplicate key fields.");
755 affirm(keyFieldCount <= managedFieldCount,
756 "JDO metadata: key fields exceed managed fields.");
757
758
759 for (final Enumeration e = classFile.fields().elements();
760 e.hasMoreElements();) {
761 final ClassField field = (ClassField)e.nextElement();
762 final String name = field.name().asString();
763 final String sig = field.signature().asString();
764 final String userFieldName = userClassName + "." + name;
765
766 if (false) {
767 System.out.println("Analyzer.scanFields(): scanning "
768 + className + "." + name + " : " + sig);
769 }
770
771
772 if (name.startsWith("jdo")) {
773 final Object f = jdoLikeFields.put(name, field);
774 affirm(f == null);
775 }
776
777
778 if (!managedFieldNamesSet.contains(name)) {
779 affirm(!meta.isManagedField(className, name));
780
781
782 affirm(!keyFieldNamesSet.contains(name),
783 ("JDO metadata: reported the field " + userFieldName
784 + " to be non-managed but key."));
785 continue;
786 }
787 affirm(meta.isManagedField(className, name));
788
789
790 affirm(!field.isStatic(),
791 ("JDO metadata: reported the field " + userFieldName
792 + " to be managed though it's static."));
793
794
795 affirm(!field.isFinal(),
796 ("JDO metadata: reported the field " + userFieldName
797 + " to be managed though it's final."));
798
799
800
801
802
803
804
805
806
807
808
809 }
810
811
812 final int[] managedFieldFlags
813 = meta.getFieldFlags(className, managedFieldNames);
814
815
816
817 int j = 0;
818 keyFieldIndexes = new int[keyFieldCount];
819 final String[] managedFieldSigs = new String[managedFieldCount];
820 final int[] managedFieldMods = new int[managedFieldCount];
821 for (int i = 0; i < managedFieldCount; i++) {
822 final String name = managedFieldNames[i];
823 affirm(name != null);
824
825
826 final ClassField field = (ClassField)annotatedFieldMap.get(name);
827 affirm(field != null,
828 ("The managed field " + userClassName + "." + name +
829 " is not declared by the class."));
830 affirm(!field.isStatic(),
831 ("The managed field " + userClassName + "." + name +
832 " is static."));
833 affirm(!field.isFinal(),
834 ("The managed field " + userClassName + "." + name +
835 " is final."));
836
837
838 annotatedFieldMap.remove(name);
839
840
841 if (keyFieldNamesSet.contains(name)) {
842 affirm(meta.isKeyField(className, name));
843 keyFieldIndexes[j++] = i;
844 }
845
846
847 managedFieldSigs[i] = field.signature().asString();
848 managedFieldMods[i] = field.access();
849
850
851
852
853 if (!field.isTransient()) {
854 managedFieldFlags[i] |= EnhancerMetaData.SERIALIZABLE;
855 }
856
857 if (false) {
858 System.out.println("managed field: "
859 + className + "." + name + " : {");
860 System.out.println(" sigs = " + managedFieldSigs[i]);
861 System.out.println(" mods = "
862 + Integer.toHexString(managedFieldMods[i]));
863 System.out.println(" flags = "
864 + Integer.toHexString(managedFieldFlags[i]));
865 }
866 }
867
868
869 affirm(keyFieldIndexes.length == keyFieldCount);
870 affirm(keyFieldCount <= managedFieldCount);
871 affirm(managedFieldNames.length == managedFieldCount);
872 affirm(managedFieldSigs.length == managedFieldCount);
873 affirm(managedFieldMods.length == managedFieldCount);
874 affirm(managedFieldFlags.length == managedFieldCount);
875 affirm(managedFieldCount <= annotatedFieldCount);
876
877
878 if (managedFieldCount == annotatedFieldCount) {
879
880 annotatedFieldNames = managedFieldNames;
881 annotatedFieldSigs = managedFieldSigs;
882 annotatedFieldMods = managedFieldMods;
883 annotatedFieldFlags = managedFieldFlags;
884 } else {
885
886 annotatedFieldNames = new String[annotatedFieldCount];
887 annotatedFieldSigs = new String[annotatedFieldCount];
888 annotatedFieldMods = new int[annotatedFieldCount];
889 annotatedFieldFlags = new int[annotatedFieldCount];
890 int i = managedFieldCount;
891 System.arraycopy(managedFieldNames, 0, annotatedFieldNames, 0, i);
892 System.arraycopy(managedFieldSigs, 0, annotatedFieldSigs, 0, i);
893 System.arraycopy(managedFieldMods, 0, annotatedFieldMods, 0, i);
894 System.arraycopy(managedFieldFlags, 0, annotatedFieldFlags, 0, i);
895
896
897 for (Iterator k = annotatedFieldMap.entrySet().iterator();
898 k.hasNext();) {
899 final Map.Entry entry = (Map.Entry)k.next();
900 final String name = (String)entry.getKey();
901 final ClassField field = (ClassField)entry.getValue();
902 affirm(name.equals(field.name().asString()));
903
904 affirm(!field.isStatic(),
905 ("The managed field " + userClassName + "." + name +
906 " is static."));
907
908
909 annotatedFieldNames[i] = name;
910 annotatedFieldSigs[i] = field.signature().asString();
911 annotatedFieldMods[i] = field.access();
912 annotatedFieldFlags[i] = 0x0;
913 i++;
914 }
915 affirm(i == annotatedFieldCount);
916 }
917
918
919 affirm(keyFieldIndexes.length == keyFieldCount);
920 affirm(keyFieldCount <= managedFieldCount);
921 affirm(annotatedFieldNames.length == annotatedFieldCount);
922 affirm(annotatedFieldSigs.length == annotatedFieldCount);
923 affirm(annotatedFieldMods.length == annotatedFieldCount);
924 affirm(annotatedFieldFlags.length == annotatedFieldCount);
925 affirm(managedFieldCount <= annotatedFieldCount);
926 }
927
928 /***
929 * Scans the methods of a ClassFile.
930 */
931 private void scanMethods()
932 {
933
934 for (final Enumeration e = classFile.methods().elements();
935 e.hasMoreElements();) {
936 final ClassMethod method = (ClassMethod)e.nextElement();
937 final String name = method.name().asString();
938 final String sig = method.signature().asString();
939 affirm(name != null);
940 affirm(sig != null);
941
942 final String key = methodKey(name, sig);
943 affirm(key != null);
944
945
946 if (!method.isAbstract() && !method.isNative()) {
947 final Object m = annotatableMethods.put(key, method);
948 affirm(m == null);
949 }
950
951
952 if (name.startsWith("jdo")) {
953 final Object m = jdoLikeMethods.put(key, method);
954 affirm(m == null);
955 continue;
956 }
957
958
959 if (name.equals(NameHelper.constructorName())
960 && sig.equals(NameHelper.constructorSig())) {
961 hasDefaultConstructor = true;
962 continue;
963 }
964
965
966 if (name.equals(JAVA_clinit_Name)
967 && sig.equals(JAVA_clinit_Sig)) {
968 hasStaticInitializer = true;
969 continue;
970 }
971
972
973 if (name.equals(JAVA_Object_clone_Name)
974 && sig.equals(JAVA_Object_clone_Sig)) {
975 hasCloneMethod = true;
976 continue;
977 }
978
979
980 if (name.equals(JAVA_Object_writeObject_Name)
981 && sig.equals(JAVA_Object_writeObject_Sig)) {
982 hasWriteObjectMethod = true;
983 continue;
984 }
985
986
987 if (name.equals(JAVA_Object_writeReplace_Name)
988 && sig.equals(JAVA_Object_writeReplace_Sig)) {
989 hasWriteReplaceMethod = true;
990 continue;
991 }
992
993
994 if (name.equals(JAVA_Object_readObject_Name)
995 && sig.equals(JAVA_Object_readObject_Sig)) {
996 hasReadObjectMethod = true;
997
998
999 Object m = annotatableMethods.remove(key);
1000 affirm(m != null);
1001 continue;
1002 }
1003 }
1004
1005
1006 if (hasDefaultConstructor) {
1007 env.message(getI18N("enhancer.class_has_default_constructor"));
1008 } else {
1009 env.message(getI18N("enhancer.class_has_not_default_constructor"));
1010 }
1011
1012
1013 if (hasStaticInitializer) {
1014 env.message(getI18N("enhancer.class_has_static_initializer"));
1015 } else {
1016 env.message(getI18N("enhancer.class_has_not_static_initializer"));
1017 }
1018
1019
1020 if (hasCloneMethod) {
1021 env.message(getI18N("enhancer.class_has_clone_method"));
1022 } else {
1023 env.message(getI18N("enhancer.class_has_not_clone_method"));
1024 }
1025
1026
1027 if (hasWriteObjectMethod) {
1028 env.message(getI18N("enhancer.class_has_writeObject_method"));
1029 } else {
1030 env.message(getI18N("enhancer.class_has_not_writeObject_method"));
1031 }
1032
1033
1034 if (hasWriteReplaceMethod) {
1035 env.message(getI18N("enhancer.class_has_writeReplace_method"));
1036 } else {
1037 env.message(getI18N("enhancer.class_has_not_writeReplace_method"));
1038 }
1039
1040
1041 if (hasReadObjectMethod) {
1042 env.message(getI18N("enhancer.class_has_readObject_method"));
1043 } else {
1044 env.message(getI18N("enhancer.class_has_not_readObject_method"));
1045 }
1046 }
1047
1048 private void checkGenericAugmentation()
1049 {
1050 scanForImplementsPC();
1051 scanForGenericJDOFields();
1052 scanForGenericJDOMethods();
1053
1054 final boolean all
1055 = (hasImplementsPC && hasGenericJDOFields && hasGenericJDOMethods);
1056
1057 final boolean none
1058 = !(hasImplementsPC
1059 || hasGenericJDOFields || hasGenericJDOMethods);
1060
1061 if (all ^ none) {
1062 hasGenericJDOMembers = hasImplementsPC;
1063 env.message(
1064 getI18N("enhancer.class_has_generic_jdo_members",
1065 String.valueOf(hasGenericJDOMembers)));
1066
1067
1068
1069 return;
1070 }
1071
1072 final String key
1073 = "enhancer.class_has_inconsistently_declared_jdo_members";
1074 if (hasGenericJDOFields && !hasGenericJDOMethods) {
1075 env.error(
1076 getI18N(key,
1077 userClassName,
1078 "<generic jdo fields>",
1079 "<generic jdo methods>"));
1080 } else if (!hasGenericJDOFields && hasGenericJDOMethods) {
1081 env.error(
1082 getI18N(key,
1083 userClassName,
1084 "<generic jdo methods>",
1085 "<generic jdo fields>"));
1086 } else if (!hasGenericJDOFields && !hasGenericJDOMethods) {
1087 env.error(
1088 getI18N(key,
1089 userClassName,
1090 "<implements " + JDO_PersistenceCapable_Name + ">",
1091 "<generic jdo members>"));
1092 } else {
1093 env.error(
1094 getI18N(key,
1095 userClassName,
1096 "<generic jdo members>",
1097 "<implements " + JDO_PersistenceCapable_Name + ">"));
1098 }
1099 }
1100
1101 private void checkSpecificAugmentation()
1102 {
1103 scanForSpecificJDOFields();
1104 scanForSpecificJDOMethods();
1105
1106 final boolean all
1107 = (hasSpecificJDOFields && hasSpecificJDOMethods);
1108
1109 final boolean none
1110 = !(hasSpecificJDOFields || hasSpecificJDOMethods);
1111
1112 if (all ^ none) {
1113 hasSpecificJDOMembers = hasSpecificJDOFields;
1114 env.message(
1115 getI18N("enhancer.class_has_specific_jdo_members",
1116 String.valueOf(hasSpecificJDOMembers)));
1117 return;
1118 }
1119
1120 final String key
1121 = "enhancer.class_has_inconsistently_declared_jdo_members";
1122 if (hasSpecificJDOFields && !hasSpecificJDOMethods) {
1123 env.error(
1124 getI18N(key,
1125 userClassName,
1126 "<specific jdo fields>",
1127 "<specific jdo methods>"));
1128 } else {
1129 env.error(
1130 getI18N(key,
1131 userClassName,
1132 "<specific jdo methods>",
1133 "<specific jdo fields>"));
1134 }
1135 }
1136
1137 private void checkCallbackAugmentation()
1138 {
1139 scanForCallbackJDOMethods();
1140 env.message(
1141 getI18N("enhancer.class_has_callback_jdo_methods",
1142 String.valueOf(hasCallbackJDOMethods)));
1143 }
1144
1145 private void checkPCFeasibility()
1146 {
1147 if (!hasDefaultConstructor) {
1148 env.error(
1149 getI18N("enhancer.class_missing_default_constructor",
1150 userClassName));
1151 }
1152 }
1153
1154 /***
1155 * Scans the class for implementing the PC interface.
1156 */
1157 private void scanForImplementsPC()
1158 {
1159 hasImplementsPC = false;
1160 for (final Iterator ifc = classFile.interfaces().iterator();
1161 ifc.hasNext();) {
1162 final ConstClass i = (ConstClass)ifc.next();
1163 if (i.asString().equals(JDO_PersistenceCapable_Path)) {
1164 hasImplementsPC = true;
1165 break;
1166 }
1167 }
1168 env.message(
1169 getI18N("enhancer.class_implements_jdo_pc",
1170 String.valueOf(hasImplementsPC)));
1171 }
1172
1173 /***
1174 * Scans for JDO fields of generic augmentation.
1175 */
1176 private void scanForGenericJDOFields()
1177 {
1178
1179 if (jdoLikeFields.isEmpty()) {
1180 hasGenericJDOFields = false;
1181 env.message(
1182 getI18N("enhancer.class_has_generic_jdo_fields",
1183 String.valueOf(hasGenericJDOFields)));
1184 return;
1185 }
1186
1187
1188 final Set found = new HashSet(10);
1189 final Set missing = new HashSet(10);
1190
1191 scanJDOField(JDO_PC_jdoStateManager_Name,
1192 JDO_PC_jdoStateManager_Sig,
1193 JDO_PC_jdoStateManager_Mods,
1194 found, missing);
1195 scanJDOField(JDO_PC_jdoFlags_Name,
1196 JDO_PC_jdoFlags_Sig,
1197 JDO_PC_jdoFlags_Mods,
1198 found, missing);
1199
1200 if (found.isEmpty() ^ missing.isEmpty()) {
1201 hasGenericJDOFields = missing.isEmpty();
1202 env.message(
1203 getI18N("enhancer.class_has_generic_jdo_fields",
1204 String.valueOf(hasGenericJDOFields)));
1205 return;
1206 }
1207
1208 reportInconsistentJDOMembers(found, missing);
1209 }
1210
1211 /***
1212 * Scans for JDO methods of generic augmentation.
1213 */
1214 private void scanForGenericJDOMethods()
1215 {
1216
1217 if (jdoLikeMethods.isEmpty()) {
1218 hasGenericJDOMethods = false;
1219 env.message(
1220 getI18N("enhancer.class_has_generic_jdo_methods",
1221 String.valueOf(hasGenericJDOMethods)));
1222 return;
1223 }
1224
1225
1226 final Set found = new HashSet(30);
1227 final Set missing = new HashSet(30);
1228
1229 scanJDOMethod(JDO_PC_jdoReplaceStateManager_Name,
1230 JDO_PC_jdoReplaceStateManager_Sig,
1231 JDO_PC_jdoReplaceStateManager_Mods,
1232 found, missing);
1233 scanJDOMethod(JDO_PC_jdoReplaceFlags_Name,
1234 JDO_PC_jdoReplaceFlags_Sig,
1235 JDO_PC_jdoReplaceFlags_Mods,
1236 found, missing);
1237 scanJDOMethod(JDO_PC_jdoGetPersistenceManager_Name,
1238 JDO_PC_jdoGetPersistenceManager_Sig,
1239 JDO_PC_jdoGetPersistenceManager_Mods,
1240 found, missing);
1241 scanJDOMethod(JDO_PC_jdoGetObjectId_Name,
1242 JDO_PC_jdoGetObjectId_Sig,
1243 JDO_PC_jdoGetObjectId_Mods,
1244 found, missing);
1245 scanJDOMethod(JDO_PC_jdoGetTransactionalObjectId_Name,
1246 JDO_PC_jdoGetTransactionalObjectId_Sig,
1247 JDO_PC_jdoGetTransactionalObjectId_Mods,
1248 found, missing);
1249 scanJDOMethod(JDO_PC_jdoIsPersistent_Name,
1250 JDO_PC_jdoIsPersistent_Sig,
1251 JDO_PC_jdoIsPersistent_Mods,
1252 found, missing);
1253 scanJDOMethod(JDO_PC_jdoIsTransactional_Name,
1254 JDO_PC_jdoIsTransactional_Sig,
1255 JDO_PC_jdoIsTransactional_Mods,
1256 found, missing);
1257 scanJDOMethod(JDO_PC_jdoIsNew_Name,
1258 JDO_PC_jdoIsNew_Sig,
1259 JDO_PC_jdoIsNew_Mods,
1260 found, missing);
1261 scanJDOMethod(JDO_PC_jdoIsDeleted_Name,
1262 JDO_PC_jdoIsDeleted_Sig,
1263 JDO_PC_jdoIsDeleted_Mods,
1264 found, missing);
1265 scanJDOMethod(JDO_PC_jdoIsDirty_Name,
1266 JDO_PC_jdoIsDirty_Sig,
1267 JDO_PC_jdoIsDirty_Mods,
1268 found, missing);
1269 scanJDOMethod(JDO_PC_jdoMakeDirty_Name,
1270 JDO_PC_jdoMakeDirty_Sig,
1271 JDO_PC_jdoMakeDirty_Mods,
1272 found, missing);
1273 scanJDOMethod(JDO_PC_jdoPreSerialize_Name,
1274 JDO_PC_jdoPreSerialize_Sig,
1275 JDO_PC_jdoPreSerialize_Mods,
1276 found, missing);
1277 scanJDOMethod(JDO_PC_jdoReplaceFields_Name,
1278 JDO_PC_jdoReplaceFields_Sig,
1279 JDO_PC_jdoReplaceFields_Mods,
1280 found, missing);
1281 scanJDOMethod(JDO_PC_jdoProvideFields_Name,
1282 JDO_PC_jdoProvideFields_Sig,
1283 JDO_PC_jdoProvideFields_Mods,
1284 found, missing);
1285
1286 if (found.isEmpty() ^ missing.isEmpty()) {
1287 hasGenericJDOMethods = missing.isEmpty();
1288 env.message(
1289 getI18N("enhancer.class_has_generic_jdo_methods",
1290 String.valueOf(hasGenericJDOMethods)));
1291 return;
1292 }
1293
1294 reportInconsistentJDOMembers(found, missing);
1295 }
1296
1297 /***
1298 * Scans for JDO fields of specific augmentation.
1299 */
1300 private void scanForSpecificJDOFields()
1301 {
1302
1303 if (jdoLikeFields.isEmpty()) {
1304 hasSpecificJDOFields = false;
1305 env.message(
1306 getI18N("enhancer.class_has_specific_jdo_fields",
1307 String.valueOf(hasSpecificJDOFields)));
1308 return;
1309 }
1310
1311
1312 final Set found = new HashSet(10);
1313 final Set missing = new HashSet(10);
1314
1315 scanJDOField(JDO_PC_jdoInheritedFieldCount_Name,
1316 JDO_PC_jdoInheritedFieldCount_Sig,
1317 JDO_PC_jdoInheritedFieldCount_Mods,
1318 found, missing);
1319 scanJDOField(JDO_PC_jdoFieldNames_Name,
1320 JDO_PC_jdoFieldNames_Sig,
1321 JDO_PC_jdoFieldNames_Mods,
1322 found, missing);
1323 scanJDOField(JDO_PC_jdoFieldTypes_Name,
1324 JDO_PC_jdoFieldTypes_Sig,
1325 JDO_PC_jdoFieldTypes_Mods,
1326 found, missing);
1327 scanJDOField(JDO_PC_jdoFieldFlags_Name,
1328 JDO_PC_jdoFieldFlags_Sig,
1329 JDO_PC_jdoFieldFlags_Mods,
1330 found, missing);
1331 scanJDOField(JDO_PC_jdoPersistenceCapableSuperclass_Name,
1332 JDO_PC_jdoPersistenceCapableSuperclass_Sig,
1333 JDO_PC_jdoPersistenceCapableSuperclass_Mods,
1334 found, missing);
1335
1336 if (found.isEmpty() ^ missing.isEmpty()) {
1337 hasSpecificJDOFields = missing.isEmpty();
1338 env.message(
1339 getI18N("enhancer.class_has_specific_jdo_fields",
1340 String.valueOf(hasSpecificJDOFields)));
1341 return;
1342 }
1343
1344 reportInconsistentJDOMembers(found, missing);
1345 }
1346
1347 /***
1348 * Scans for JDO methods of specific augmentation.
1349 */
1350 private void scanForSpecificJDOMethods()
1351 {
1352
1353 if (jdoLikeMethods.isEmpty()) {
1354 hasSpecificJDOMethods = false;
1355 env.message(
1356 getI18N("enhancer.class_has_specific_jdo_methods",
1357 String.valueOf(hasSpecificJDOMethods)));
1358 return;
1359 }
1360
1361
1362 final Set found = new HashSet(30);
1363 final Set missing = new HashSet(30);
1364
1365 scanJDOMethod(JDO_PC_jdoGetManagedFieldCount_Name,
1366 JDO_PC_jdoGetManagedFieldCount_Sig,
1367 JDO_PC_jdoGetManagedFieldCount_Mods,
1368 found, missing);
1369 scanJDOMethod(JDO_PC_jdoNewInstance_Name,
1370 JDO_PC_jdoNewInstance_Sig,
1371 JDO_PC_jdoNewInstance_Mods,
1372 found, missing);
1373 scanJDOMethod(JDO_PC_jdoNewInstance_Name,
1374 JDO_PC_jdoNewInstance_Sig,
1375 JDO_PC_jdoNewInstance_Mods,
1376 found, missing);
1377 scanJDOMethod(JDO_PC_jdoNewObjectIdInstance_Name,
1378 JDO_PC_jdoNewObjectIdInstance_Sig,
1379 JDO_PC_jdoNewObjectIdInstance_Mods,
1380 found, missing);
1381 scanJDOMethod(JDO_PC_jdoNewObjectIdInstance_Name,
1382 JDO_PC_jdoNewObjectIdInstance_Sig,
1383 JDO_PC_jdoNewObjectIdInstance_Mods,
1384 found, missing);
1385 scanJDOMethod(JDO_PC_jdoCopyKeyFieldsToObjectId_Name,
1386 JDO_PC_jdoCopyKeyFieldsToObjectId_Sig,
1387 JDO_PC_jdoCopyKeyFieldsToObjectId_Mods,
1388 found, missing);
1389 scanJDOMethod(JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Name,
1390 JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Sig,
1391 JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Mods,
1392 found, missing);
1393 scanJDOMethod(JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Name,
1394 JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Sig,
1395 JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Mods,
1396 found, missing);
1397 scanJDOMethod(JDO_PC_jdoReplaceField_Name,
1398 JDO_PC_jdoReplaceField_Sig,
1399 JDO_PC_jdoReplaceField_Mods,
1400 found, missing);
1401 scanJDOMethod(JDO_PC_jdoProvideField_Name,
1402 JDO_PC_jdoProvideField_Sig,
1403 JDO_PC_jdoProvideField_Mods,
1404 found, missing);
1405 scanJDOMethod(JDO_PC_jdoCopyFields_Name,
1406 JDO_PC_jdoCopyFields_Sig,
1407 JDO_PC_jdoCopyFields_Mods,
1408 found, missing);
1409 scanJDOMethod(JDO_PC_jdoCopyField_Name,
1410 JDONameHelper.getJDO_PC_jdoCopyField_Sig(className),
1411 JDO_PC_jdoCopyField_Mods,
1412 found, missing);
1413
1414 if (found.isEmpty() ^ missing.isEmpty()) {
1415 hasSpecificJDOMethods = missing.isEmpty();
1416 env.message(
1417 getI18N("enhancer.class_has_specific_jdo_methods",
1418 String.valueOf(hasSpecificJDOMethods)));
1419 return;
1420 }
1421
1422 reportInconsistentJDOMembers(found, missing);
1423 }
1424
1425 /***
1426 * Scans for JDO methods of generic augmentation.
1427 */
1428 private void scanForCallbackJDOMethods()
1429 {
1430
1431 if (jdoLikeMethods.isEmpty()) {
1432 hasCallbackJDOMethods = false;
1433 env.message(
1434 getI18N("enhancer.class_has_callback_jdo_methods",
1435 String.valueOf(hasCallbackJDOMethods)));
1436 return;
1437 }
1438
1439
1440 final Set found = new HashSet(30);
1441 final Set missing = new HashSet(30);
1442 final boolean annotatable = true;
1443
1444 scanJDOMethod(JDO_IC_jdoPostLoad_Name,
1445 JDO_IC_jdoPostLoad_Sig,
1446 JDO_IC_jdoPostLoad_Mods,
1447 found, missing, !annotatable);
1448
1449 scanJDOMethod(JDO_IC_jdoPreStore_Name,
1450 JDO_IC_jdoPreStore_Sig,
1451 JDO_IC_jdoPreStore_Mods,
1452 found, missing, annotatable);
1453
1454 scanJDOMethod(JDO_IC_jdoPreClear_Name,
1455 JDO_IC_jdoPreClear_Sig,
1456 JDO_IC_jdoPreClear_Mods,
1457 found, missing, !annotatable);
1458
1459 scanJDOMethod(JDO_IC_jdoPreDelete_Name,
1460 JDO_IC_jdoPreDelete_Sig,
1461 JDO_IC_jdoPreDelete_Mods,
1462 found, missing, annotatable);
1463
1464
1465 if (!found.isEmpty()) {
1466 hasCallbackJDOMethods = true;
1467 env.message(
1468 getI18N("enhancer.class_has_callback_jdo_methods",
1469 String.valueOf(hasCallbackJDOMethods)));
1470 }
1471 }
1472
1473 /***
1474 * Verifies a JDO field signature.
1475 */
1476 private void scanJDOField(String fieldName,
1477 String expectedSig,
1478 int expectedMods,
1479 Set found,
1480 Set missing)
1481 {
1482 final ClassField field = (ClassField)jdoLikeFields.get(fieldName);
1483 if (field == null) {
1484 missing.add(fieldName);
1485 return;
1486 }
1487 found.add(fieldName);
1488
1489 final String foundSig = field.signature().asString();
1490 final int foundMods = field.access();
1491 if (!expectedSig.equals(foundSig) || expectedMods != foundMods) {
1492 env.error(
1493 getI18N("enhancer.class_has_illegally_declared_jdo_member",
1494 new Object[]{ userClassName,
1495 fieldName,
1496 expectedSig,
1497 foundSig,
1498 new Integer(expectedMods),
1499 new Integer(foundMods) }));
1500 }
1501 }
1502
1503 /***
1504 * Verifies a JDO method signature.
1505 */
1506 private void scanJDOMethod(String methodName,
1507 String expectedSig,
1508 int expectedMods,
1509 Set found,
1510 Set missing)
1511 {
1512 scanJDOMethod(methodName, expectedSig, expectedMods,
1513 found, missing, true);
1514 }
1515
1516 /***
1517 * Verifies a JDO method signature.
1518 */
1519 private void scanJDOMethod(String methodName,
1520 String expectedSig,
1521 int expectedMods,
1522 Set found,
1523 Set missing,
1524 boolean annotatable)
1525 {
1526 final String key = methodKey(methodName, expectedSig);
1527 final ClassMethod method = (ClassMethod)jdoLikeMethods.get(key);
1528 if (method == null) {
1529 missing.add(key);
1530 return;
1531 }
1532 found.add(key);
1533
1534 final String foundSig = method.signature().asString();
1535 final int foundMods = method.access();
1536 if (!expectedSig.equals(foundSig) || expectedMods != foundMods) {
1537 env.error(
1538 getI18N("enhancer.class_has_illegally_declared_jdo_member",
1539 new Object[]{ userClassName,
1540 methodName,
1541 expectedSig,
1542 foundSig,
1543 new Integer(expectedMods),
1544 new Integer(foundMods) }));
1545 }
1546
1547
1548 if (!annotatable) {
1549 Object m = annotatableMethods.remove(key);
1550 affirm(m != null);
1551 }
1552 }
1553
1554 /***
1555 * Reports an error for some found/missing JDO fields or methods.
1556 */
1557 private void reportInconsistentJDOMembers(Set found,
1558 Set missing)
1559 {
1560 final Iterator fi = found.iterator();
1561 final StringBuffer f = new StringBuffer((String)fi.next());
1562 while (fi.hasNext()) {
1563 f.append(", " + fi.next());
1564 }
1565
1566 final Iterator mi = found.iterator();
1567 final StringBuffer m = new StringBuffer((String)mi.next());
1568 while (mi.hasNext()) {
1569 m.append(", " + mi.next());
1570 }
1571
1572 env.error(
1573 getI18N("enhancer.class_has_inconsistently_declared_jdo_members",
1574 userClassName, f.toString(), m.toString()));
1575 }
1576
1577
1578
1579 static private String methodKey(String name,
1580 String sig)
1581 {
1582 affirm(name != null);
1583 affirm(sig != null && sig.charAt(0) == '(' && sig.indexOf(')') > 0);
1584 final String parms = sig.substring(0, sig.indexOf(')') + 1);
1585 return (name + parms);
1586 }
1587 }