1 23 24 29 30 package com.sun.jdo.api.persistence.support.util; 31 32 33 import java.lang.reflect.*; 34 import java.util.List ; 35 import java.util.ArrayList ; 36 import java.io.PrintStream ; 37 38 import com.sun.jdo.api.persistence.support.PersistenceManager; 40 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceCapable; 41 import com.sun.jdo.spi.persistence.support.sqlstore.StateManager; 42 43 46 public class AugmentationTest 47 { 48 static boolean debug = false; 49 static final PrintStream out = System.out; 50 51 static final void affirm(boolean cond) 52 { 53 if (debug && !cond) 54 throw new RuntimeException ("affirmion failed."); 55 } 56 57 static final void affirm(Object obj) 58 { 59 if (debug && obj == null) 60 throw new RuntimeException ("affirmion failed: obj = null"); 61 } 62 63 static String toString(int mods, 64 Class type, 65 String name) 66 { 67 final StringBuffer s = new StringBuffer (); 68 s.append(Modifier.toString(mods)); 69 s.append(" "); 70 s.append(type.getName()); 71 s.append(" "); 72 s.append(name); 73 return s.toString(); 74 } 75 76 static String toString(int mods, 77 String name, 78 Class [] params) 79 { 80 final StringBuffer s = new StringBuffer (); 81 s.append(Modifier.toString(mods)); 82 s.append(" "); 83 s.append(name); 84 s.append("("); 85 final int j = params.length - 1; 86 for (int i = 0; i <= j; i++) { 87 s.append(params[i].getName()); 88 if (i < j) 89 s.append(","); 90 } 91 s.append(")"); 92 return s.toString(); 93 } 94 95 static String toString(int mods, 96 Class result, 97 String name, 98 Class [] params) 99 { 100 final StringBuffer s = new StringBuffer (); 101 s.append(Modifier.toString(mods)); 102 s.append(" "); 103 s.append(result.getName()); 104 s.append(" "); 105 s.append(name); 106 s.append("("); 107 final int j = params.length - 1; 108 for (int i = 0; i <= j; i++) { 109 s.append(params[i].getName()); 110 if (i < j) 111 s.append(","); 112 } 113 s.append(")"); 114 return s.toString(); 115 } 116 117 public final int AFFIRMATIVE = 1; 118 public final int NEGATIVE = 0; 119 public final int ERROR = -1; 120 121 boolean verbose; 122 boolean requirePC; 123 List classes; 124 String className; 125 Class classClass; 126 127 public AugmentationTest() 128 {} 129 130 final void println() 131 { 132 out.println(); 133 } 134 135 final void println(String msg) 136 { 137 out.println(msg); 138 } 139 140 final void verbose() 141 { 142 if (verbose) 143 out.println(); 144 } 145 146 final void verbose(String msg) 147 { 148 if (verbose) 149 out.println(msg); 150 } 151 152 public int testLoadingClass() 153 { 154 verbose(); 155 verbose("Test loading class: " + className + " ..."); 156 157 try { 158 classClass = Class.forName(className); 159 verbose("+++ loaded class"); 160 return AFFIRMATIVE; 161 } catch (LinkageError err) { 162 println("!!! ERROR: linkage error when loading class: " 163 + className); 164 println(" error: " + err); 165 println("!!! failed loading class"); 166 return ERROR; 167 } catch (ClassNotFoundException ex) { 168 println("!!! ERROR: class not found: " + className); 169 println(" exception: " + ex); 170 println("!!! failed loading class"); 171 return ERROR; 172 } 173 } 174 175 int implementsInterface(Class intf) 176 { 177 final Class [] interfaces = classClass.getInterfaces(); 178 for (int i = interfaces.length - 1; i >= 0; i--) { 179 if (interfaces[i].equals(intf)) { 180 verbose("+++ implements interface: " + intf.getName()); 181 return AFFIRMATIVE; 182 } 183 } 184 verbose("--- not implementing interface: " + intf.getName()); 185 return NEGATIVE; 186 } 187 188 int hasField(int mods, 189 Class type, 190 String name) 191 { 192 try { 193 final Field field = classClass.getField(name); 194 195 if (field.getModifiers() != mods 196 || !field.getType().equals(type)) { 197 println("!!! ERROR: field declaration: "); 198 println(" expected: " + toString(mods, type, name)); 199 println(" found: " + field.toString()); 200 return ERROR; 201 } 202 203 verbose("+++ has field: " + field.toString()); 204 return AFFIRMATIVE; 205 206 } catch (NoSuchFieldException ex) { 207 verbose("--- no field: " + toString(mods, type, name)); 208 return NEGATIVE; 209 } 210 } 211 212 int hasConstructor(int mods, 213 Class [] params) 214 { 215 try { 216 final Constructor ctor = classClass.getConstructor(params); 217 218 if (ctor.getModifiers() != mods) { 219 println("!!! ERROR: constructor declaration: "); 220 println(" expected: " + toString(mods, className, params)); 221 println(" found: " + ctor.toString()); 222 return ERROR; 223 } 224 225 verbose("+++ has constructor: " + ctor.toString()); 226 return AFFIRMATIVE; 227 228 } catch (NoSuchMethodException ex) { 229 verbose("--- no constructor: " 230 + toString(mods, className, params)); 231 return NEGATIVE; 232 } 233 } 234 235 int hasMethod(int mods, 236 Class result, 237 String name, 238 Class [] params) 239 { 240 try { 241 final Method method = classClass.getMethod(name, params); 242 243 if (method.getModifiers() != mods 244 || !method.getReturnType().equals(result)) { 245 println("!!! ERROR: method declaration: "); 246 println(" expected: " + toString(mods, result, name, params)); 247 println(" found: " + method.toString()); 248 return ERROR; 249 } 250 251 verbose("+++ has method: " + method.toString()); 252 return AFFIRMATIVE; 253 254 } catch (NoSuchMethodException ex) { 255 verbose("--- no method: " 256 + toString(mods, result, name, params)); 257 return NEGATIVE; 258 } 259 } 260 261 public int hasGenericAugmentation() 262 { 263 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE); 264 265 verbose(); 266 verbose("Check for \"generic\" augmentation ..."); 267 affirm(classClass); 268 269 final int nofFeatures = 15; 270 final int[] r = new int[nofFeatures]; 271 { 272 int i = 0; 273 r[i++] = implementsInterface(PersistenceCapable.class); 274 275 r[i++] = hasField(Modifier.PUBLIC | Modifier.TRANSIENT, 276 StateManager.class, 277 "jdoStateManager"); 278 r[i++] = hasField(Modifier.PUBLIC | Modifier.TRANSIENT, 279 byte.class, 280 "jdoFlags"); 281 282 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 283 StateManager.class, 284 "jdoGetStateManager", 285 new Class []{}); 286 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 287 void.class, 288 "jdoSetStateManager", 289 new Class []{StateManager.class}); 290 291 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 292 byte.class, 293 "jdoGetFlags", 294 new Class []{}); 295 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 296 void.class, 297 "jdoSetFlags", 298 new Class []{byte.class}); 299 300 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 301 PersistenceManager.class, 302 "jdoGetPersistenceManager", 303 new Class []{}); 304 305 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 306 Object .class, 307 "jdoGetObjectId", 308 new Class []{}); 309 310 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 311 boolean.class, 312 "jdoIsDirty", 313 new Class []{}); 314 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 315 boolean.class, 316 "jdoIsTransactional", 317 new Class []{}); 318 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 319 boolean.class, 320 "jdoIsPersistent", 321 new Class []{}); 322 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 323 boolean.class, 324 "jdoIsNew", 325 new Class []{}); 326 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 327 boolean.class, 328 "jdoIsDeleted", 329 new Class []{}); 330 331 r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL, 332 void.class, 333 "jdoMakeDirty", 334 new Class []{String .class}); 335 affirm(i == nofFeatures); 336 } 337 338 int res = 0; 339 for (int i = 0; i < nofFeatures; i ++) { 340 final int j = r[i]; 341 affirm(ERROR <= j && j <= AFFIRMATIVE); 342 343 if (j < res) { 344 println("!!! ERROR: inconsistent \"generic\" augmentation of class: " 345 + className); 346 return ERROR; 347 } 348 349 if (j > NEGATIVE) 350 res = j; 351 } 352 353 if (res > NEGATIVE) { 354 verbose("+++ has \"generic\" augmentation"); 355 return AFFIRMATIVE; 356 } 357 358 verbose("--- no \"generic\" augmentation"); 359 return NEGATIVE; 360 } 361 362 public int hasSpecificAugmentation() 363 { 364 affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE); 365 366 verbose(); 367 verbose("Check for \"class-specific\" augmentation ..."); 368 affirm(classClass); 369 370 final int nofFeatures = 5; 371 final int[] r = new int[nofFeatures]; 372 { 373 int i = 0; 374 r[i++] = hasConstructor(Modifier.PUBLIC, 375 new Class []{StateManager.class}); 376 r[i++] = hasMethod(Modifier.PUBLIC, 377 Object .class, 378 "jdoGetField", 379 new Class []{int.class}); 380 r[i++] = hasMethod(Modifier.PUBLIC, 381 void.class, 382 "jdoSetField", 383 new Class []{int.class, Object .class}); 384 385 r[i++] = hasMethod(Modifier.PUBLIC, 386 void.class, 387 "jdoClear", 388 new Class []{}); 389 r[i++] = hasMethod(Modifier.PUBLIC, 390 Object .class, 391 "jdoNewInstance", 392 new Class []{StateManager.class}); 393 affirm(i == nofFeatures); 394 } 395 396 399 int res = 0; 400 for (int i = 0; i < nofFeatures; i++) { 401 final int j = r[i]; 402 affirm(ERROR <= j && j <= AFFIRMATIVE); 403 404 if (j < res) { 405 println("!!! ERROR: inconsistent \"class-specific\" augmentation of class: " 406 + className); 407 return ERROR; 408 } 409 410 if (j > NEGATIVE) 411 res = j; 412 } 413 414 if (res > NEGATIVE) { 415 verbose("+++ has \"class-specific\" augmentation"); 416 return AFFIRMATIVE; 417 } 418 419 verbose("--- no \"class-specific\" augmentation"); 420 return NEGATIVE; 421 } 422 423 static private final String [] transientPrefixes 424 = {"java.", 425 "javax.", 426 "com.sun.jdo."}; 427 428 public int testPCFeasibility() 429 { 430 verbose(); 431 verbose("Test feasibility of class: " + className + " ..."); 432 433 int status = AFFIRMATIVE; 434 435 final int mods = classClass.getModifiers(); 436 437 if (classClass.isPrimitive()) { 438 println("!!! ERROR: specified class is primitive type"); 439 status = ERROR; 440 } 441 442 if (classClass.isArray()) { 443 println("!!! ERROR: specified class is array"); 444 status = ERROR; 445 } 446 447 if (classClass.isInterface()) { 448 println("!!! ERROR: specified class is interface"); 449 status = ERROR; 450 } 451 452 if (Modifier.isAbstract(mods)) { 453 println("!!! ERROR: specified class is abstract"); 454 status = ERROR; 455 } 456 457 if (!Modifier.isPublic(mods)) { 458 println("!!! ERROR: specified class is not public"); 459 status = ERROR; 460 } 461 462 if (classClass.getDeclaringClass() != null) { 465 println("!!! ERROR: specified class is inner class"); 466 status = ERROR; 467 } 468 469 if (Throwable .class.isAssignableFrom(classClass)) { 470 println("!!! ERROR: specified class extends Throwable"); 471 status = ERROR; 472 } 473 474 for (int i = 0; i < transientPrefixes.length; i++) { 477 final String typePrefix = transientPrefixes[i]; 478 if (className.startsWith(typePrefix)) { 479 println("!!! ERROR: specified class starts with package prefix: " 480 + typePrefix); 481 status = ERROR; 482 } 483 } 484 485 final Class superClass = classClass.getSuperclass(); 487 if (superClass == null) { 488 println("!!! ERROR: specified class doesn't have super class"); 489 status = ERROR; 490 } else { 491 try { 492 final Class [] params = new Class []{}; 494 Constructor sctor = superClass.getConstructor(params); 495 } catch (NoSuchMethodException ex) { 496 println("!!! ERROR: super class '" + superClass.getName() 497 + "' doesn't provide default constructor"); 498 status = ERROR; 499 } 500 } 501 502 verbose(status == AFFIRMATIVE 503 ? "+++ is feasible for persistence-capability" 504 : "!!! not feasible for persistence-capability"); 505 return status; 506 } 507 508 public int testJdoConstructor() 509 { 510 verbose(); 511 verbose("Test JDO constructor ..."); 512 affirm(classClass); 513 514 try { 515 final Class [] params = new Class []{StateManager.class}; 517 final Constructor ctor = classClass.getConstructor(params); 518 519 final Object [] args = new Object []{null}; 521 final Object instance = ctor.newInstance(args); 522 523 PersistenceCapable pc = (PersistenceCapable)instance; 525 526 if (pc.jdoGetStateManager() != null) { 528 println("!!! ERROR: invokation of JDO constructor:"); 529 println(" pc.jdoStateManager != null"); 530 println("!!! failed testing JDO constructor"); 531 return ERROR; 532 } 533 534 if (pc.jdoGetFlags() != 1) { 536 println("!!! ERROR: invokation of JDO constructor:"); 537 println(" pc.jdoFlags != 0"); 538 println("!!! failed testing JDO constructor"); 539 return ERROR; 540 } 541 } catch (NoSuchMethodException ex) { 542 println("!!! ERROR: no JDO constructor"); 543 println("!!! failed testing JDO constructor"); 544 return ERROR; 545 } catch (InstantiationException ex) { 546 println("!!! ERROR: invokation of JDO constructor:"); 547 println(" exception: " + ex); 548 println("!!! failed testing JDO constructor"); 549 return ERROR; 550 } catch (IllegalAccessException ex) { 551 println("!!! ERROR: invokation of JDO constructor:"); 552 println(" exception: " + ex); 553 println("!!! failed testing JDO constructor"); 554 return ERROR; 555 } catch (InvocationTargetException ex) { 556 println("!!! ERROR: invokation of JDO constructor:"); 557 println(" exception: " + ex); 558 println(" nested: " + ex.getTargetException()); 559 println("!!! failed testing JDO constructor"); 560 return ERROR; 561 } 562 563 verbose("+++ tested JDO constructor"); 564 return AFFIRMATIVE; 565 } 566 567 public int test(String className) 568 { 569 affirm(className); 570 this.className = className; 571 572 verbose(); 573 verbose("-------------------------------------------------------------------------------"); 574 verbose(); 575 verbose("Test class for augmentation: " 576 + className + " ..."); 577 578 if (testLoadingClass() < AFFIRMATIVE) { 579 return ERROR; 580 } 581 582 final int r0 = hasGenericAugmentation(); 583 final int r1 = hasSpecificAugmentation(); 584 585 if (r1 < NEGATIVE || r0 < NEGATIVE) { 586 return ERROR; 587 } 588 affirm(r1 >= NEGATIVE && r0 >= NEGATIVE); 589 590 if (r1 == NEGATIVE && r0 == NEGATIVE) { 591 if (requirePC) { 592 println(); 593 println("!!! ERROR: class not augmented: " + className); 594 return ERROR; 595 } 596 597 println(); 598 println("--- not augmented: " + className); 599 return NEGATIVE; 600 } 601 602 if (r0 == NEGATIVE) { 603 println(); 604 println("!!! ERROR: class lacking \"generic\" augmentation: " 605 + className); 606 return ERROR; 607 } 608 609 if (r1 == NEGATIVE) { 610 println(); 611 println("!!! ERROR: class lacking \"class-specific\" augmentation: " 612 + className); 613 return ERROR; 614 } 615 affirm(r1 > NEGATIVE && r0 > NEGATIVE); 616 617 final int r2 = testPCFeasibility(); 618 if (r2 < AFFIRMATIVE) { 619 return ERROR; 620 } 621 622 final int r3 = testJdoConstructor(); 623 if (r3 < AFFIRMATIVE) { 624 return ERROR; 625 } 626 627 println(); 628 println("+++ augmented: " + className); 629 return AFFIRMATIVE; 630 } 631 632 public int test(boolean verbose, 633 boolean requirePC, 634 List classes) 635 { 636 affirm(classes); 637 this.verbose = verbose; 638 this.requirePC = requirePC; 639 640 final int all = classes.size(); 641 642 println(); 643 println("AugmentationTest: Testing classes for being enhanced for persistence-capability"); 644 645 int failed = 0; 646 for (int i = 0; i < all; i++) { 647 if (test((String )classes.get(i)) < NEGATIVE) { 648 failed++; 649 } 650 } 651 final int passed = all - failed; 652 653 println(); 654 println("AugmentationTest: Summary: TESTED: " + all 655 + " PASSED: " + passed 656 + " FAILED: " + failed); 657 return failed; 658 } 659 660 661 664 static void usage() 665 { 666 out.println(); 667 out.println("Usage: AugmentationTest <options> <classes>..."); 668 out.println(); 669 out.println("This class tests if classes have been correctly enhanced"); 670 out.println("for persistence-capability (\"augmented\")."); 671 out.println(); 672 out.println("Options include:"); 673 out.println(" -h, --help print usage"); 674 out.println(" -v, --verbose enable verbose output"); 675 out.println(" -pc, --requirePC require all classes to be augmented"); 676 out.println(); 677 out.println("A non-zero value is returned in case of any errors."); 678 out.println(); 679 } 680 681 static public void main(String [] argv) 682 { 683 boolean verbose = false; 685 boolean requirePC = false; 686 List classes = new ArrayList (); 687 for (int i = 0; i < argv.length; i++) { 688 String arg = argv[i]; 689 if (arg.equals("-h") || arg.equals("--help")) { 690 usage(); 691 return; 692 } 693 if (arg.equals("-v") || arg.equals("--verbose")) { 694 verbose = true; 695 continue; 696 } 697 if (arg.equals("-pc") || arg.equals("--requirePC")) { 698 requirePC = true; 699 continue; 700 } 701 if (arg.equals("--debug")) { 702 debug = true; 703 continue; 704 } 705 if (arg.startsWith("-")) { 706 out.println(); 707 out.println("Unrecognized option: " + arg); 708 usage(); 709 return; 710 } 711 classes.add(arg); 712 } 713 714 if (classes.isEmpty()) { 716 out.println(); 717 out.println("Missing classes argument"); 718 usage(); 719 return; 720 } 721 722 if (debug) { 723 out.println("options:"); 724 out.println(" verbose = " + verbose); 725 out.println(" requirePC = " + requirePC); 726 out.print(" classes ="); 727 for (int i = 0; i < classes.size(); i++) 728 out.print(" " + classes.get(i)); 729 out.println(); 730 } 731 732 final AugmentationTest test = new AugmentationTest(); 733 final int r = test.test(verbose, requirePC, classes); 734 System.exit(r); 735 } 736 } 737 | Popular Tags |