1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.impl.enhancer.util;
19
20 import java.lang.reflect.Modifier;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Constructor;
24
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Arrays;
29 import java.util.HashSet;
30
31 import java.io.PrintWriter;
32 import java.io.StringWriter;
33 import java.io.IOException;
34
35 import org.apache.jdo.impl.enhancer.EnhancerFatalError;
36 import org.apache.jdo.impl.enhancer.EnhancerUserException;
37 import org.apache.jdo.impl.enhancer.JdoMetaMain;
38 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
39 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
40
41
42
43
44 /***
45 * Utility class for testing a class file for correct augmentation.
46 *
47 * @author Martin Zaun
48 */
49 public class AugmentationTest
50 extends JdoMetaMain
51 {
52
53 static public final int AFFIRMATIVE = 1;
54 static public final int NEGATIVE = 0;
55 static public final int ERROR = -1;
56
57 static private final String[] transientPrefixes
58 = {"java.",
59 "javax." };
60
61 static String toString(int mods,
62 Class type,
63 String name)
64 {
65 final StringBuffer s = new StringBuffer();
66 s.append(Modifier.toString(mods));
67 s.append(" ");
68 s.append(type.getName());
69 s.append(" ");
70 s.append(name);
71 return s.toString();
72 }
73
74 static String toString(int mods,
75 String name,
76 Class[] params)
77 {
78 final StringBuffer s = new StringBuffer();
79 s.append(Modifier.toString(mods));
80 s.append(" ");
81 s.append(name);
82 s.append("(");
83 final int j = params.length - 1;
84 for (int i = 0; i <= j; i++) {
85 s.append(params[i].getName());
86 if (i < j)
87 s.append(",");
88 }
89 s.append(")");
90 return s.toString();
91 }
92
93 static String toString(int mods,
94 Class result,
95 String name,
96 Class[] params)
97 {
98 final StringBuffer s = new StringBuffer();
99 s.append(Modifier.toString(mods));
100 s.append(" ");
101 s.append(result.getName());
102 s.append(" ");
103 s.append(name);
104 s.append("(");
105 final int j = params.length - 1;
106 for (int i = 0; i <= j; i++) {
107 s.append(params[i].getName());
108 if (i < j)
109 s.append(",");
110 }
111 s.append(")");
112 return s.toString();
113 }
114
115 static String toString(int mods,
116 Class result,
117 String name,
118 Class[] params,
119 Class[] ex)
120 {
121 final StringBuffer s = new StringBuffer();
122 s.append(toString(mods, result, name, params));
123 s.append(" throws ");
124 final int j = ex.length - 1;
125 for (int i = 0; i <= j; i++) {
126 s.append(ex[i].getName());
127 if (i < j)
128 s.append(",");
129 }
130 return s.toString();
131 }
132
133
134
135
136 private boolean verbose;
137 private String className;
138 private String classPath;
139 private Class classObject;
140 private HashSet fields;
141 private HashSet methods;
142
143
144 private ClassLoader classLoader;
145 private Class persistenceManagerClass;
146 private Class instanceCallbacksClass;
147 private Class persistenceCapableClass;
148 private Class objectIdFieldSupplierClass;
149 private Class objectIdFieldConsumerClass;
150 private Class stateManagerClass;
151
152 public AugmentationTest(PrintWriter out,
153 PrintWriter err)
154 {
155 super(out, err);
156 }
157
158 private int implementsInterface(PrintWriter out,
159 Class intf)
160 {
161 final Class[] interfaces = classObject.getInterfaces();
162 for (int i = interfaces.length - 1; i >= 0; i--) {
163 if (interfaces[i].equals(intf)) {
164 out.println(" +++ implements interface: "
165 + intf.getName());
166 return AFFIRMATIVE;
167 }
168 }
169 out.println(" --- not implementing interface: "
170 + intf.getName());
171 return NEGATIVE;
172 }
173
174 private int hasField(PrintWriter out,
175 int mods,
176 Class type,
177 String name)
178 {
179 try {
180 final Field field = classObject.getDeclaredField(name);
181 fields.remove(field);
182
183 if ((field.getModifiers() & mods) != mods) {
184 out.println(" !!! ERROR: field declaration: unmatched modifiers");
185 out.println(" expected: "
186 + toString(mods, type, name));
187 out.println(" found: "
188 + field.toString());
189 return ERROR;
190 }
191
192 if (!field.getType().equals(type)) {
193 out.println(" !!! ERROR: field declaration: unexpected type");
194 out.println(" expected: "
195 + toString(mods, type, name));
196 out.println(" found: "
197 + field.toString());
198 return ERROR;
199 }
200
201 out.println(" +++ has field: "
202 + field.toString());
203 return AFFIRMATIVE;
204 } catch (NoSuchFieldException ex) {
205 out.println(" --- no field: "
206 + toString(mods, type, name));
207 return NEGATIVE;
208 }
209 }
210
211 private int hasConstructor(PrintWriter out,
212 int mods,
213 Class[] params)
214 {
215 try {
216 final Constructor ctor = classObject.getDeclaredConstructor(params);
217
218 if ((ctor.getModifiers() & mods) != mods) {
219 out.println(" !!! ERROR: constructor declaration: unmatched modifiers");
220 out.println(" expected: "
221 + toString(mods, className, params));
222 out.println(" found: "
223 + ctor.toString());
224 return ERROR;
225 }
226
227 out.println(" +++ has constructor: "
228 + ctor.toString());
229 return AFFIRMATIVE;
230 } catch (NoSuchMethodException ex) {
231 out.println(" --- no constructor: "
232 + toString(mods, className, params));
233 return NEGATIVE;
234 }
235 }
236
237 private int hasMethod(PrintWriter out,
238 int mods,
239 Class result,
240 String name,
241 Class[] params,
242 Class[] exepts)
243 {
244 try {
245 final Method method = classObject.getDeclaredMethod(name, params);
246 methods.remove(method);
247
248 if ((method.getModifiers() & mods) != mods) {
249 out.println(" !!! ERROR: method declaration: unmatched modifiers");
250 out.println(" expected: "
251 + toString(mods, result, name, params));
252 out.println(" found: "
253 + method.toString());
254 return ERROR;
255 }
256
257 if (!method.getReturnType().equals(result)) {
258 out.println(" !!! ERROR: method declaration: unexpected result type");
259 out.println(" expected: "
260 + toString(mods, result, name, params));
261 out.println(" found: "
262 + method.toString());
263 return ERROR;
264 }
265
266 final Collection c0 = Arrays.asList(exepts);
267 final Collection c1 = Arrays.asList(method.getExceptionTypes());
268 if (!c0.containsAll(c1)) {
269 out.println(" !!! ERROR: method declaration: unexpected exceptions");
270 out.println(" expected: "
271 + toString(mods, result, name, params, exepts));
272 out.println(" found: "
273 + method.toString());
274 return ERROR;
275 }
276 if (!c1.containsAll(c0)) {
277 out.println(" !!! ERROR: method declaration: unmatched exceptions");
278 out.println(" expected: "
279 + toString(mods, result, name, params, exepts));
280 out.println(" found: "
281 + method.toString());
282 return ERROR;
283 }
284
285 out.println(" +++ has method: "
286 + method.toString());
287 return AFFIRMATIVE;
288 } catch (NoSuchMethodException ex) {
289 out.println(" --- no method: "
290 + toString(mods, result, name, params));
291 return NEGATIVE;
292 }
293 }
294
295 private int hasMethod(PrintWriter out,
296 int mods,
297 Class result,
298 String name,
299 Class[] params)
300 {
301 return hasMethod(out, mods, result, name, params, new Class[]{});
302 }
303
304 private int evaluate(int nofFeatures,
305 int[] r)
306 {
307 affirm(nofFeatures <= r.length);
308
309 int res = 0;
310 for (int i = 0; i < nofFeatures; i++) {
311 final int j = r[i];
312 affirm(ERROR <= j && j <= AFFIRMATIVE);
313
314 if (j < ERROR) {
315 return ERROR;
316 }
317
318 if (j > NEGATIVE) {
319 res++;
320 }
321 }
322 affirm(res >= 0);
323
324 if (res >= nofFeatures) {
325 return AFFIRMATIVE;
326 }
327 return NEGATIVE;
328 }
329
330 private int hasGenericAugmentation(PrintWriter out)
331 {
332 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
333 affirm(classObject);
334
335 final int nofFeatures = 18;
336 final int[] r = new int[nofFeatures];
337 {
338 int i = 0;
339
340 r[i++] = hasField(
341 out,
342 Modifier.PROTECTED | Modifier.TRANSIENT,
343 stateManagerClass,
344 "jdoStateManager");
345
346 r[i++] = hasField(
347 out,
348 Modifier.PROTECTED | Modifier.TRANSIENT,
349 byte.class,
350 "jdoFlags");
351
352 r[i++] = hasMethod(
353 out,
354 Modifier.PUBLIC
355 | Modifier.FINAL
356 | Modifier.SYNCHRONIZED,
357 void.class,
358 "jdoReplaceStateManager",
359 new Class[]{stateManagerClass});
360
361 r[i++] = hasMethod(
362 out,
363 Modifier.PUBLIC | Modifier.FINAL,
364 void.class,
365 "jdoReplaceFlags",
366 new Class[]{});
367
368 r[i++] = hasMethod(
369 out,
370 Modifier.PUBLIC | Modifier.FINAL,
371 persistenceManagerClass,
372 "jdoGetPersistenceManager",
373 new Class[]{});
374
375 r[i++] = hasMethod(
376 out,
377 Modifier.PUBLIC | Modifier.FINAL,
378 Object.class,
379 "jdoGetObjectId",
380 new Class[]{});
381
382 r[i++] = hasMethod(
383 out,
384 Modifier.PUBLIC | Modifier.FINAL,
385 Object.class,
386 "jdoGetTransactionalObjectId",
387 new Class[]{});
388
389 r[i++] = hasMethod(
390 out,
391 Modifier.PUBLIC | Modifier.FINAL,
392 Object.class,
393 "jdoGetVersion",
394 new Class[]{});
395
396 r[i++] = hasMethod(
397 out,
398 Modifier.PUBLIC | Modifier.FINAL,
399 boolean.class,
400 "jdoIsPersistent",
401 new Class[]{});
402 r[i++] = hasMethod(
403 out,
404 Modifier.PUBLIC | Modifier.FINAL,
405 boolean.class,
406 "jdoIsTransactional",
407 new Class[]{});
408 r[i++] = hasMethod(
409 out,
410 Modifier.PUBLIC | Modifier.FINAL,
411 boolean.class,
412 "jdoIsNew",
413 new Class[]{});
414 r[i++] = hasMethod(
415 out,
416 Modifier.PUBLIC | Modifier.FINAL,
417 boolean.class,
418 "jdoIsDeleted",
419 new Class[]{});
420 r[i++] = hasMethod(
421 out,
422 Modifier.PUBLIC | Modifier.FINAL,
423 boolean.class,
424 "jdoIsDirty",
425 new Class[]{});
426 r[i++] = hasMethod(
427 out,
428 Modifier.PUBLIC | Modifier.FINAL,
429 boolean.class,
430 "jdoIsDetached",
431 new Class[]{});
432
433 r[i++] = hasMethod(
434 out,
435 Modifier.PUBLIC | Modifier.FINAL,
436 void.class,
437 "jdoMakeDirty",
438 new Class[]{String.class});
439
440 r[i++] = hasMethod(
441 out,
442 Modifier.PUBLIC | Modifier.FINAL,
443 void.class,
444 "jdoReplaceFields",
445 new Class[]{int[].class});
446
447 r[i++] = hasMethod(
448 out,
449 Modifier.PUBLIC | Modifier.FINAL,
450 void.class,
451 "jdoProvideFields",
452 new Class[]{int[].class});
453
454 r[i++] = hasMethod(
455 out,
456 Modifier.PROTECTED | Modifier.FINAL,
457 void.class,
458 "jdoPreSerialize",
459 new Class[]{});
460
461 affirm(i == nofFeatures);
462 }
463
464 return evaluate(nofFeatures, r);
465 }
466
467 private int hasSpecificAugmentation(PrintWriter out)
468 {
469 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
470 affirm(classObject);
471
472 final int nofFeatures = 15;
473 final int[] r = new int[nofFeatures];
474 {
475 int i = 0;
476
477 r[i++] = implementsInterface(
478 out,
479 persistenceCapableClass);
480
481 r[i++] = hasField(
482 out,
483 Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
484 int.class,
485 "jdoInheritedFieldCount");
486
487 r[i++] = hasField(
488 out,
489 Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
490 String[].class,
491 "jdoFieldNames");
492
493 r[i++] = hasField(
494 out,
495 Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
496 Class[].class,
497 "jdoFieldTypes");
498
499 r[i++] = hasField(
500 out,
501 Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
502 byte[].class,
503 "jdoFieldFlags");
504
505 r[i++] = hasField(
506 out,
507 Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
508 Class.class,
509 "jdoPersistenceCapableSuperclass");
510
511 r[i++] = hasMethod(
512 out,
513 Modifier.PROTECTED | Modifier.STATIC,
514 int.class,
515 "jdoGetManagedFieldCount",
516 new Class[]{});
517
518 r[i++] = hasMethod(
519 out,
520 Modifier.PUBLIC,
521 persistenceCapableClass,
522 "jdoNewInstance",
523 new Class[]{stateManagerClass});
524
525 r[i++] = hasMethod(
526 out,
527 Modifier.PUBLIC,
528 persistenceCapableClass,
529 "jdoNewInstance",
530 new Class[]{stateManagerClass, Object.class});
531
532 r[i++] = hasMethod(
533 out,
534 Modifier.PUBLIC,
535 void.class,
536 "jdoReplaceField",
537 new Class[]{int.class});
538
539 r[i++] = hasMethod(
540 out,
541 Modifier.PUBLIC,
542 void.class,
543 "jdoProvideField",
544 new Class[]{int.class});
545
546 r[i++] = hasMethod(
547 out,
548 Modifier.PUBLIC,
549 void.class,
550 "jdoCopyFields",
551 new Class[]{Object.class, int[].class});
552
553 r[i++] = hasMethod(
554 out,
555 Modifier.PROTECTED | Modifier.FINAL,
556 void.class,
557 "jdoCopyField",
558 new Class[]{classObject, int.class});
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 affirm(i == nofFeatures-2);
581
582 }
583
584
585 return evaluate(nofFeatures - 2, r);
586 }
587
588 private int hasKeyHandlingAugmentation(PrintWriter out)
589 {
590 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
591 affirm(classObject);
592
593 final int nofFeatures = 6;
594 final int[] r = new int[nofFeatures];
595 {
596 int i = 0;
597
598 r[i++] = hasMethod(
599 out,
600 Modifier.PUBLIC,
601 Object.class,
602 "jdoNewObjectIdInstance",
603 new Class[]{});
604
605 r[i++] = hasMethod(
606 out,
607 Modifier.PUBLIC,
608 Object.class,
609 "jdoNewObjectIdInstance",
610 new Class[]{Object.class});
611
612 r[i++] = hasMethod(
613 out,
614 Modifier.PUBLIC,
615 void.class,
616 "jdoCopyKeyFieldsToObjectId",
617 new Class[]{Object.class});
618
619 r[i++] = hasMethod(
620 out,
621 Modifier.PUBLIC,
622 void.class,
623 "jdoCopyKeyFieldsToObjectId",
624 new Class[]{objectIdFieldSupplierClass, Object.class});
625
626 r[i++] = hasMethod(
627 out,
628 Modifier.PROTECTED,
629 void.class,
630 "jdoCopyKeyFieldsFromObjectId",
631 new Class[]{Object.class});
632
633 r[i++] = hasMethod(
634 out,
635 Modifier.PUBLIC,
636 void.class,
637 "jdoCopyKeyFieldsFromObjectId",
638 new Class[]{objectIdFieldConsumerClass, Object.class});
639
640 affirm(i == nofFeatures);
641 }
642
643 return evaluate(nofFeatures, r);
644 }
645
646 private int hasAccessorMutators(PrintWriter out)
647 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
648 {
649 affirm(classObject);
650 int res = NEGATIVE;
651
652
653 final HashSet managedFields = new HashSet();
654 for (Iterator i = new HashSet(methods).iterator(); i.hasNext();) {
655 final Method method = (Method)i.next();
656 final String name = method.getName();
657
658 if (!name.startsWith("jdoGet") && !name.startsWith("jdoSet")) {
659 continue;
660 }
661 final String fieldName = name.substring(6);
662
663
664 final Field field;
665 try {
666 field = classObject.getDeclaredField(fieldName);
667 } catch (NoSuchFieldException ex) {
668 out.println(" !!! ERROR: potential jdo accessor/mutator method doesn't match declared field");
669 out.println(" found method: " + method);
670 methods.remove(method);
671 res = ERROR;
672 continue;
673 }
674
675
676 final int fieldMods = field.getModifiers();
677 if ((fieldMods & Modifier.STATIC) != 0) {
678 out.println(" !!! ERROR: potential jdo accessor/mutator method matches a static field");
679 out.println(" found method: " + method);
680 out.println(" found field: " + field);
681 methods.remove(method);
682 res = ERROR;
683 continue;
684 }
685
686
687 if (jdoMeta != null && !jdoMeta.isManagedField(classPath, fieldName)) {
688 out.println(" !!! ERROR: potential jdo accessor/mutator method matches a non-managed field");
689 out.println(" found method: " + method);
690 out.println(" found field: " + field);
691 methods.remove(method);
692 res = ERROR;
693 continue;
694 }
695
696 managedFields.add(field);
697 }
698
699
700 final String[] metaFieldNames = (jdoMeta != null
701 ? jdoMeta.getManagedFields(classPath)
702 : new String[]{});
703 for (int i = 0; i < metaFieldNames.length; i++) {
704 final String fieldName = metaFieldNames[i];
705
706
707 final Field field;
708 try {
709 field = classObject.getDeclaredField(fieldName);
710 fields.remove(field);
711 } catch (NoSuchFieldException ex) {
712 out.println(" !!! ERROR: field defined by jdo meta-data not declared in class");
713 out.println(" no declared field: " + fieldName);
714 res = ERROR;
715 continue;
716 }
717
718
719 final int fieldMods = field.getModifiers();
720 if ((fieldMods & Modifier.STATIC) != 0) {
721
722 out.println(" !!! ERROR: field defined by jdo meta-data is declared static in class");
723 out.println(" static field: " + field);
724 res = ERROR;
725 continue;
726 }
727
728 managedFields.add(field);
729 }
730
731
732 final HashSet methodSet = new HashSet(methods);
733 for (Iterator i = managedFields.iterator(); i.hasNext();) {
734 final Field field = (Field)i.next();
735 final String fieldName = field.getName();
736 final Class fieldType = field.getType();
737 final int fieldMods = field.getModifiers();
738
739
740 final int mods = (Modifier.STATIC
741 | (fieldMods
742 & (Modifier.PUBLIC
743 | Modifier.PROTECTED
744 | Modifier.PRIVATE)));
745 final String accessorName = "jdoGet" + fieldName;
746 final Class[] accessorParams = new Class[]{classObject};
747 final Class accessorReturnType = fieldType;
748 final String mutatorName = "jdoSet" + fieldName;
749 final Class[] mutatorParams = new Class[]{classObject, fieldType};
750 final Class mutatorReturnType = void.class;
751 final Class[] exeptions = new Class[]{};
752
753
754 final int r0 = hasMethod(out,
755 mods,
756 accessorReturnType,
757 accessorName,
758 accessorParams,
759 exeptions);
760 if (r0 < NEGATIVE) {
761 res = ERROR;
762 } else if (r0 == NEGATIVE) {
763 out.println(" !!! ERROR: missing or incorrect jdo accessor for declared field");
764 out.println(" field: " + field);
765 out.println(" expected: "
766 + toString(mods,
767 accessorReturnType,
768 accessorName,
769 accessorParams,
770 exeptions));
771 for (Iterator j = methodSet.iterator(); j.hasNext();) {
772 final Method method = (Method)j.next();
773 if (method.getName().equals(accessorName)) {
774 out.println(" found: " + method);
775 methods.remove(method);
776 }
777 }
778 res = ERROR;
779 }
780
781
782 final int r1 = hasMethod(out,
783 mods,
784 mutatorReturnType,
785 mutatorName,
786 mutatorParams,
787 exeptions);
788 if (r1 < NEGATIVE) {
789 res = ERROR;
790 } else if (r1 == NEGATIVE) {
791 out.println(" !!! ERROR: missing or incorrect jdo mutator for declared field");
792 out.println(" field: " + field);
793 out.println(" expected: "
794 + toString(mods,
795 mutatorReturnType,
796 mutatorName,
797 mutatorParams,
798 exeptions));
799 for (Iterator j = methodSet.iterator(); j.hasNext();) {
800 final Method method = (Method)j.next();
801 if (method.getName().equals(accessorName)) {
802 out.println(" found: " + method);
803 methods.remove(method);
804 }
805 }
806 res = ERROR;
807 }
808
809
810 if (res == NEGATIVE) {
811 res = AFFIRMATIVE;
812 }
813 }
814
815 return res;
816 }
817
818 private int hasInstanceCallbacks(PrintWriter out)
819 {
820 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
821 affirm(classObject);
822
823 final int nofFeatures = 5;
824 final int[] r = new int[nofFeatures];
825 {
826 int i = 0;
827
828 r[i++] = implementsInterface(
829 out,
830 instanceCallbacksClass);
831
832 r[i++] = hasMethod(
833 out,
834 Modifier.PUBLIC,
835 void.class,
836 "jdoPostLoad",
837 new Class[]{});
838
839 r[i++] = hasMethod(
840 out,
841 Modifier.PUBLIC,
842 void.class,
843 "jdoPreStore",
844 new Class[]{});
845
846 r[i++] = hasMethod(
847 out,
848 Modifier.PUBLIC,
849 void.class,
850 "jdoPreClear",
851 new Class[]{});
852
853 r[i++] = hasMethod(
854 out,
855 Modifier.PUBLIC,
856 void.class,
857 "jdoPreDelete",
858 new Class[]{});
859
860 affirm(i == nofFeatures);
861 }
862
863 return evaluate(1, r);
864 }
865
866 private int testPCFeasibility(PrintWriter out)
867 {
868 affirm(classObject);
869
870 int status = AFFIRMATIVE;
871
872 final int mods = classObject.getModifiers();
873
874
875 StringWriter s = new StringWriter();
876 final int hasCtor = hasConstructor(new PrintWriter(s),
877 0,
878 new Class[]{});
879 if (hasCtor <= NEGATIVE) {
880 status = ERROR;
881 } else {
882 if (verbose) {
883 out.print(s.toString());
884 }
885 }
886
887
888 if (classObject.isInterface()) {
889 out.println(" !!! ERROR: class is interface");
890 status = ERROR;
891 } else {
892 if (verbose) {
893 out.println(" +++ is not an interface");
894 }
895 }
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910 if (classObject.getDeclaringClass() != null
911 && !Modifier.isStatic(mods)) {
912 out.println(" !!! ERROR: class is inner class");
913 status = ERROR;
914 } else {
915 if (verbose) {
916 out.println(" +++ is not an inner class");
917 }
918 }
919
920
921 for (int i = 0; i < transientPrefixes.length; i++) {
922 final String typePrefix = transientPrefixes[i];
923 if (className.startsWith(typePrefix)) {
924 out.println(" !!! ERROR: class is in package: "
925 + typePrefix + "..");
926 status = ERROR;
927 } else {
928 if (verbose) {
929 out.println(" +++ is not in package: "
930 + typePrefix + "..");
931 }
932 }
933 }
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959 if (classObject.isPrimitive()) {
960 out.println(" !!! ERROR: class is of primitive type");
961 status = ERROR;
962 }
963
964
965 if (classObject.isArray()) {
966 out.println(" !!! ERROR: class is of array type");
967 status = ERROR;
968 }
969
970
971 if (classObject.getSuperclass() == null) {
972 out.println(" !!! ERROR: class doesn't have super class");
973 status = ERROR;
974 }
975
976 return status;
977 }
978
979 private int hasNoIllegalJdoMembers(PrintWriter out)
980 {
981 affirm(classObject);
982 int res = AFFIRMATIVE;
983
984 for (Iterator i = new HashSet(methods).iterator(); i.hasNext();) {
985 final Method method = (Method)i.next();
986 final String name = method.getName();
987 if (name.startsWith("jdo")) {
988 out.println(" !!! ERROR: illegal jdo method");
989 out.println(" found method: " + method);
990 methods.remove(method);
991 res = ERROR;
992 }
993 }
994
995 for (Iterator i = new HashSet(fields).iterator(); i.hasNext();) {
996 final Field field = (Field)i.next();
997 final String name = field.getName();
998 if (name.startsWith("jdo")) {
999 out.println(" !!! ERROR: illegal jdo field");
1000 out.println(" found field: " + field);
1001 fields.remove(field);
1002 res = ERROR;
1003 }
1004 }
1005
1006 return res;
1007 }
1008
1009 private int testAugmentation(PrintWriter out)
1010 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
1011 {
1012 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
1013 affirm(classObject);
1014 affirm(className);
1015
1016
1017 StringWriter s = new StringWriter();
1018 int r0 = hasSpecificAugmentation(new PrintWriter(s));
1019
1020 if (r0 < NEGATIVE) {
1021 out.println(" !!! ERROR: inconsistent \"class-specific\" augmentation");
1022 out.println(s.toString());
1023 r0 = ERROR;
1024 } else if (r0 == NEGATIVE) {
1025 if (jdoMeta != null && jdoMeta.isPersistenceCapableClass(classPath)) {
1026 out.println(" !!! ERROR: missing \"class-specific\" augmentation");
1027 out.println(s.toString());
1028 r0 = ERROR;
1029 } else {
1030 if (verbose) {
1031 out.println(" --- no \"class-specific\" augmentation");
1032 out.println(s.toString());
1033 }
1034 }
1035 } else {
1036 affirm(r0 > NEGATIVE);
1037 if (jdoMeta != null && !jdoMeta.isPersistenceCapableClass(classPath)) {
1038 out.println(" !!! ERROR: unexpected \"class-specific\" augmentation");
1039 out.println(s.toString());
1040 r0 = ERROR;
1041 } else {
1042 if (verbose) {
1043 out.println(" +++ has correct \"class-specific\" augmentation");
1044 out.println(s.toString());
1045 }
1046 }
1047 }
1048
1049
1050 s = new StringWriter();
1051 int r1 = hasKeyHandlingAugmentation(new PrintWriter(s));
1052
1053 if (r1 < NEGATIVE) {
1054 out.println(" !!! ERROR: inconsistent \"key-handling\" augmentation");
1055 out.println(s.toString());
1056 r1 = ERROR;
1057 } else if (r1 == NEGATIVE) {
1058 if (jdoMeta != null
1059 && (jdoMeta.isPersistenceCapableClass(classPath)
1060 && jdoMeta.getKeyClass(classPath) != null)) {
1061 out.println(" !!! ERROR: missing \"key-handling\" augmentation");
1062 out.println(s.toString());
1063 r1 = ERROR;
1064 } else {
1065 if (verbose) {
1066 out.println(" --- no \"key-handling\" augmentation");
1067 out.println(s.toString());
1068 }
1069 }
1070 } else {
1071 affirm(r1 > NEGATIVE);
1072 if (r0 == NEGATIVE
1073 || (jdoMeta != null
1074 && (!jdoMeta.isPersistenceCapableRootClass(classPath)
1075 && jdoMeta.getKeyClass(classPath) == null))) {
1076 out.println(" !!! ERROR: unexpected \"key-handling\" augmentation");
1077 out.println(s.toString());
1078 r1 = ERROR;
1079 } else {
1080 if (verbose) {
1081 out.println(" +++ has correct \"key-handling\" augmentation");
1082 out.println(s.toString());
1083 }
1084 }
1085 }
1086 affirm(r0 != NEGATIVE || r1 <= NEGATIVE);
1087
1088
1089 s = new StringWriter();
1090 int r2 = hasGenericAugmentation(new PrintWriter(s));
1091
1092 if (r2 < NEGATIVE) {
1093 out.println(" !!! ERROR: inconsistent \"generic\" augmentation");
1094 out.println(s.toString());
1095 r2 = ERROR;
1096 } else if (r2 == NEGATIVE) {
1097 if (jdoMeta != null
1098 && jdoMeta.isPersistenceCapableRootClass(classPath)) {
1099 out.println(" !!! ERROR: missing \"generic\" augmentation");
1100 out.println(s.toString());
1101 r2 = ERROR;
1102 } else {
1103 if (verbose) {
1104 out.println(" --- no \"generic\" augmentation");
1105 out.println(s.toString());
1106 }
1107 }
1108 } else {
1109 affirm(r2 > NEGATIVE);
1110 if (r0 == NEGATIVE
1111 || (jdoMeta != null
1112 && !jdoMeta.isPersistenceCapableRootClass(classPath))) {
1113 out.println(" !!! ERROR: unexpected \"generic\" augmentation");
1114 out.println(s.toString());
1115 r2 = ERROR;
1116 } else {
1117 if (verbose) {
1118 out.println(" +++ has correct \"generic\" augmentation");
1119 out.println(s.toString());
1120 }
1121 }
1122 }
1123 affirm(r0 != NEGATIVE || r2 <= NEGATIVE);
1124
1125
1126 s = new StringWriter();
1127 int r3 = hasAccessorMutators(new PrintWriter(s));
1128
1129 if (r3 < NEGATIVE) {
1130 out.println(" !!! ERROR: inconsistent \"accessor/mutator\" augmentation");
1131 out.println(s.toString());
1132 } else if (r3 == NEGATIVE) {
1133 if (verbose) {
1134 out.println(" --- no \"accessor/mutator\" augmentation");
1135 out.println(s.toString());
1136 }
1137 } else {
1138 affirm(r3 > NEGATIVE);
1139 if (r0 == NEGATIVE) {
1140 out.println(" !!! ERROR: unexpected \"accessor/mutator\" augmentation");
1141 out.println(s.toString());
1142 r3 = ERROR;
1143 } else {
1144 if (verbose) {
1145 out.println(" +++ has correct \"accessor/mutator\" augmentation");
1146 out.println(s.toString());
1147 }
1148 }
1149 }
1150 affirm(r0 != NEGATIVE || r3 <= NEGATIVE);
1151
1152
1153 s = new StringWriter();
1154 int r4 = hasInstanceCallbacks(new PrintWriter(s));
1155
1156 if (r4 < NEGATIVE) {
1157 out.println(" !!! ERROR: inconsistent instance callback features");
1158 out.println(s.toString());
1159 } else if (r4 == NEGATIVE) {
1160 if (verbose) {
1161 out.println(" --- no instance callback features");
1162 out.println(s.toString());
1163 }
1164 } else {
1165 affirm(r4 > NEGATIVE);
1166 if (verbose) {
1167 out.println(" +++ has instance callback features");
1168 out.println(s.toString());
1169 }
1170 }
1171
1172
1173 s = new StringWriter();
1174 int r5 = hasNoIllegalJdoMembers(new PrintWriter(s));
1175 if (r5 <= NEGATIVE) {
1176 out.println(" !!! ERROR: illegal jdo member");
1177 out.println(s.toString());
1178 } else {
1179 if (verbose) {
1180 out.println(" +++ no illegal jdo member");
1181 out.println(s.toString());
1182 }
1183 }
1184
1185
1186 if (r0 < NEGATIVE || r1 < NEGATIVE || r2 < NEGATIVE || r3 < NEGATIVE
1187 || r4 < NEGATIVE || r5 < NEGATIVE) {
1188 return ERROR;
1189 }
1190
1191
1192 if (r0 == NEGATIVE) {
1193 affirm(r1 == NEGATIVE);
1194 affirm(r2 == NEGATIVE);
1195 affirm(r3 == NEGATIVE);
1196 affirm(r4 >= NEGATIVE);
1197 affirm(r5 > NEGATIVE);
1198 return NEGATIVE;
1199 }
1200
1201
1202 s = new StringWriter();
1203 int r6 = testPCFeasibility(new PrintWriter(s));
1204 if (r6 <= NEGATIVE) {
1205 out.println(" !!! not feasible for persistence-capability");
1206 out.println(s.toString());
1207 r6 = ERROR;
1208 } else {
1209 if (verbose) {
1210 out.println(" +++ is feasible for persistence-capability");
1211 out.println(s.toString());
1212 }
1213 }
1214
1215
1216 if (r6 < NEGATIVE) {
1217 return ERROR;
1218 }
1219
1220
1221 return AFFIRMATIVE;
1222 }
1223
1224 private int testLoadingClass(PrintWriter out)
1225 {
1226 try {
1227 classObject = classLoader.loadClass(className);
1228 out.println(" +++ loaded class");
1229 } catch (LinkageError err) {
1230 out.println(" !!! ERROR: linkage error when loading class: "
1231 + className);
1232 out.println(" error: " + err);
1233 return ERROR;
1234 } catch (ClassNotFoundException ex) {
1235 out.println(" !!! ERROR: class not found: " + className);
1236 out.println(" exception: " + ex);
1237 return ERROR;
1238 }
1239
1240 try {
1241 fields = new HashSet();
1242 fields.addAll(Arrays.asList(classObject.getDeclaredFields()));
1243 methods = new HashSet();
1244 methods.addAll(Arrays.asList(classObject.getDeclaredMethods()));
1245 } catch (SecurityException ex) {
1246 affirm(false);
1247 return ERROR;
1248 }
1249 return AFFIRMATIVE;
1250 }
1251
1252 private int test(PrintWriter out,
1253 String className)
1254 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
1255 {
1256 affirm(className);
1257 this.className = className;
1258 this.classPath = className.replace('.', '/');
1259
1260
1261 if (verbose) {
1262 out.println("-------------------------------------------------------------------------------");
1263 out.println();
1264 out.println("Test class for augmentation: "
1265 + className + " ...");
1266 }
1267
1268
1269 StringWriter s = new StringWriter();
1270 if (testLoadingClass(new PrintWriter(s)) <= NEGATIVE) {
1271 out.println();
1272 out.println("!!! ERROR: failed loading class: " + className);
1273 out.println(s.toString());
1274 return ERROR;
1275 }
1276
1277 if (verbose) {
1278 out.println();
1279 out.println("+++ loaded class: " + className);
1280 out.println(s.toString());
1281 }
1282
1283
1284 s = new StringWriter();
1285 final int r = testAugmentation(new PrintWriter(s));
1286 if (r < NEGATIVE) {
1287 out.println();
1288 out.println("!!! ERROR: incorrect augmentation: " + className);
1289 out.println(s.toString());
1290 return ERROR;
1291 }
1292
1293 if (r == NEGATIVE) {
1294 out.println();
1295 out.println("--- class not augmented: " + className);
1296 } else {
1297 out.println();
1298 out.println("+++ class augmented: " + className);
1299 }
1300 if (verbose) {
1301 out.println(s.toString());
1302 }
1303
1304 return r;
1305 }
1306
1307 protected int test(PrintWriter out,
1308 boolean verbose,
1309 List classNames)
1310 {
1311 affirm(classNames);
1312 this.verbose = verbose;
1313 final int all = classNames.size();
1314
1315 out.println();
1316 out.println("AugmentationTest: Testing Classes for JDO Persistence-Capability Enhancement");
1317
1318 int nofFailed = 0;
1319 for (int i = 0; i < all; i++) {
1320 if (test(out, (String)classNames.get(i)) < NEGATIVE) {
1321 nofFailed++;
1322 }
1323 }
1324 final int nofPassed = all - nofFailed;
1325
1326 out.println();
1327 out.println("AugmentationTest: Summary: TESTED: " + all
1328 + " PASSED: " + nofPassed
1329 + " FAILED: " + nofFailed);
1330 return nofFailed;
1331 }
1332
1333
1334
1335 /***
1336 * Initializes all components.
1337 */
1338 protected void init()
1339 throws EnhancerFatalError, EnhancerUserException
1340 {
1341 super.init();
1342 if (!options.classFileNames.isEmpty()
1343 || !options.archiveFileNames.isEmpty()) {
1344 throw new EnhancerFatalError("Sorry, this test right now only support class name arguments, not class or archive files.");
1345 }
1346 affirm(classes != null);
1347 try {
1348 classLoader = classes.getClassLoader();
1349 persistenceManagerClass
1350 = classLoader.loadClass("javax.jdo.PersistenceManager");
1351 instanceCallbacksClass
1352 = classLoader.loadClass("javax.jdo.InstanceCallbacks");
1353 persistenceCapableClass
1354 = classLoader.loadClass("javax.jdo.spi.PersistenceCapable");
1355 objectIdFieldSupplierClass
1356 = classLoader.loadClass("javax.jdo.spi.PersistenceCapable$ObjectIdFieldSupplier");
1357 objectIdFieldConsumerClass
1358 = classLoader.loadClass("javax.jdo.spi.PersistenceCapable$ObjectIdFieldConsumer");
1359 stateManagerClass
1360 = classLoader.loadClass("javax.jdo.spi.StateManager");
1361 } catch (Exception ex) {
1362 throw new EnhancerFatalError(ex);
1363 }
1364 }
1365
1366 /***
1367 * Run the augmentation test.
1368 */
1369 protected int process()
1370 {
1371
1372
1373
1374
1375
1376
1377
1378
1379 return test(out, options.verbose.value, options.classNames);
1380 }
1381
1382 /***
1383 * Runs this class
1384 */
1385 static public void main(String[] args)
1386 {
1387 final PrintWriter out = new PrintWriter(System.out, true);
1388 out.println("--> AugmentationTest.main()");
1389 final AugmentationTest main = new AugmentationTest(out, out);
1390 int res = main.run(args);
1391 out.println("<-- AugmentationTest.main(): exit = " + res);
1392 System.exit(res);
1393 }
1394 }