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