1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle. All rights reserved. 5 * 6 * $Id: BindingTest.java,v 1.1 2008/02/07 17:12:32 mark Exp $ 7 */ 8 9package com.sleepycat.persist.test; 10 11import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; 12import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY; 13import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; 14 15import java.io.File; 16import java.io.IOException; 17import java.lang.reflect.Array; 18import java.lang.reflect.Field; 19import java.math.BigInteger; 20import java.util.ArrayList; 21import java.util.Arrays; 22import java.util.Collection; 23import java.util.Comparator; 24import java.util.Date; 25import java.util.HashMap; 26import java.util.HashSet; 27import java.util.Iterator; 28import java.util.LinkedList; 29import java.util.List; 30import java.util.Locale; 31import java.util.Map; 32import java.util.Set; 33import java.util.TreeMap; 34import java.util.TreeSet; 35 36import junit.framework.TestCase; 37 38import com.sleepycat.bind.EntryBinding; 39import com.sleepycat.compat.DbCompat; 40import com.sleepycat.db.DatabaseConfig; 41import com.sleepycat.db.DatabaseEntry; 42import com.sleepycat.db.DatabaseException; 43import com.sleepycat.db.Environment; 44import com.sleepycat.db.EnvironmentConfig; 45import com.sleepycat.db.ForeignMultiKeyNullifier; 46import com.sleepycat.db.SecondaryKeyCreator; 47import com.sleepycat.db.SecondaryMultiKeyCreator; 48import com.sleepycat.persist.impl.PersistCatalog; 49import com.sleepycat.persist.impl.PersistComparator; 50import com.sleepycat.persist.impl.PersistEntityBinding; 51import com.sleepycat.persist.impl.PersistKeyBinding; 52import com.sleepycat.persist.impl.PersistKeyCreator; 53import com.sleepycat.persist.impl.SimpleCatalog; 54import com.sleepycat.persist.model.AnnotationModel; 55import com.sleepycat.persist.model.ClassMetadata; 56import com.sleepycat.persist.model.Entity; 57import com.sleepycat.persist.model.EntityMetadata; 58import com.sleepycat.persist.model.EntityModel; 59import com.sleepycat.persist.model.KeyField; 60import com.sleepycat.persist.model.Persistent; 61import com.sleepycat.persist.model.PersistentProxy; 62import com.sleepycat.persist.model.PrimaryKey; 63import com.sleepycat.persist.model.PrimaryKeyMetadata; 64import com.sleepycat.persist.model.SecondaryKey; 65import com.sleepycat.persist.model.SecondaryKeyMetadata; 66import com.sleepycat.persist.raw.RawField; 67import com.sleepycat.persist.raw.RawObject; 68import com.sleepycat.persist.raw.RawType; 69import com.sleepycat.util.test.SharedTestUtils; 70import com.sleepycat.util.test.TestEnv; 71 72/** 73 * @author Mark Hayes 74 */ 75public class BindingTest extends TestCase { 76 77 private static final String STORE_PREFIX = "persist#foo#"; 78 79 private File envHome; 80 private Environment env; 81 private EntityModel model; 82 private PersistCatalog catalog; 83 private DatabaseEntry keyEntry; 84 private DatabaseEntry dataEntry; 85 86 public void setUp() 87 throws IOException { 88 89 envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR)); 90 SharedTestUtils.emptyDir(envHome); 91 keyEntry = new DatabaseEntry(); 92 dataEntry = new DatabaseEntry(); 93 } 94 95 public void tearDown() 96 throws IOException { 97 98 if (env != null) { 99 try { 100 env.close(); 101 } catch (DatabaseException e) { 102 System.out.println("During tearDown: " + e); 103 } 104 } 105 envHome = null; 106 env = null; 107 catalog = null; 108 keyEntry = null; 109 dataEntry = null; 110 } 111 112 private void open() 113 throws IOException, DatabaseException { 114 115 EnvironmentConfig envConfig = TestEnv.BDB.getConfig(); 116 envConfig.setAllowCreate(true); 117 env = new Environment(envHome, envConfig); 118 119 openCatalog(); 120 } 121 122 private void openCatalog() 123 throws DatabaseException { 124 125 model = new AnnotationModel(); 126 model.registerClass(LocalizedTextProxy.class); 127 model.registerClass(LocaleProxy.class); 128 129 DatabaseConfig dbConfig = new DatabaseConfig(); 130 dbConfig.setAllowCreate(true); 131 DbCompat.setTypeBtree(dbConfig); 132 catalog = new PersistCatalog 133 (null, env, STORE_PREFIX, STORE_PREFIX + "catalog", dbConfig, 134 model, null, false /*rawAccess*/, null /*Store*/); 135 } 136 137 private void close() 138 throws DatabaseException { 139 140 /* Close/open/close catalog to test checks for class evolution. */ 141 catalog.close(); 142 PersistCatalog.expectNoClassChanges = true; 143 try { 144 openCatalog(); 145 } finally { 146 PersistCatalog.expectNoClassChanges = false; 147 } 148 catalog.close(); 149 catalog = null; 150 151 env.close(); 152 env = null; 153 } 154 155 public void testBasic() 156 throws IOException, DatabaseException { 157 158 open(); 159 160 checkEntity(Basic.class, 161 new Basic(1, "one", 2.2, "three")); 162 checkEntity(Basic.class, 163 new Basic(0, null, 0, null)); 164 checkEntity(Basic.class, 165 new Basic(-1, "xxx", -2, "xxx")); 166 167 checkMetadata(Basic.class.getName(), new String[][] { 168 {"id", "long"}, 169 {"one", "java.lang.String"}, 170 {"two", "double"}, 171 {"three", "java.lang.String"}, 172 }, 173 0 /*priKeyIndex*/, null); 174 175 close(); 176 } 177 178 @Entity 179 static class Basic implements MyEntity { 180 181 @PrimaryKey 182 private long id; 183 private String one; 184 private double two; 185 private String three; 186 187 private Basic() { } 188 189 private Basic(long id, String one, double two, String three) { 190 this.id = id; 191 this.one = one; 192 this.two = two; 193 this.three = three; 194 } 195 196 public String getBasicOne() { 197 return one; 198 } 199 200 public Object getPriKeyObject() { 201 return id; 202 } 203 204 public void validate(Object other) { 205 Basic o = (Basic) other; 206 TestCase.assertEquals(id, o.id); 207 TestCase.assertTrue(nullOrEqual(one, o.one)); 208 TestCase.assertEquals(two, o.two); 209 TestCase.assertTrue(nullOrEqual(three, o.three)); 210 if (one == three) { 211 TestCase.assertSame(o.one, o.three); 212 } 213 } 214 215 @Override 216 public String toString() { 217 return "" + id + ' ' + one + ' ' + two; 218 } 219 } 220 221 public void testSimpleTypes() 222 throws IOException, DatabaseException { 223 224 open(); 225 226 checkEntity(SimpleTypes.class, new SimpleTypes()); 227 228 checkMetadata(SimpleTypes.class.getName(), new String[][] { 229 {"f0", "boolean"}, 230 {"f1", "char"}, 231 {"f2", "byte"}, 232 {"f3", "short"}, 233 {"f4", "int"}, 234 {"f5", "long"}, 235 {"f6", "float"}, 236 {"f7", "double"}, 237 {"f8", "java.lang.String"}, 238 {"f9", "java.math.BigInteger"}, 239 //{"f10", "java.math.BigDecimal"}, 240 {"f11", "java.util.Date"}, 241 {"f12", "java.lang.Boolean"}, 242 {"f13", "java.lang.Character"}, 243 {"f14", "java.lang.Byte"}, 244 {"f15", "java.lang.Short"}, 245 {"f16", "java.lang.Integer"}, 246 {"f17", "java.lang.Long"}, 247 {"f18", "java.lang.Float"}, 248 {"f19", "java.lang.Double"}, 249 }, 250 0 /*priKeyIndex*/, null); 251 252 close(); 253 } 254 255 @Entity 256 static class SimpleTypes implements MyEntity { 257 258 @PrimaryKey 259 private boolean f0 = true; 260 private char f1 = 'a'; 261 private byte f2 = 123; 262 private short f3 = 123; 263 private int f4 = 123; 264 private long f5 = 123; 265 private float f6 = 123.4f; 266 private double f7 = 123.4; 267 private String f8 = "xxx"; 268 private BigInteger f9 = BigInteger.valueOf(123); 269 //private BigDecimal f10 = BigDecimal.valueOf(123.4); 270 private Date f11 = new Date(); 271 private Boolean f12 = true; 272 private Character f13 = 'a'; 273 private Byte f14 = 123; 274 private Short f15 = 123; 275 private Integer f16 = 123; 276 private Long f17 = 123L; 277 private Float f18 = 123.4f; 278 private Double f19 = 123.4; 279 280 SimpleTypes() { } 281 282 public Object getPriKeyObject() { 283 return f0; 284 } 285 286 public void validate(Object other) { 287 SimpleTypes o = (SimpleTypes) other; 288 TestCase.assertEquals(f0, o.f0); 289 TestCase.assertEquals(f1, o.f1); 290 TestCase.assertEquals(f2, o.f2); 291 TestCase.assertEquals(f3, o.f3); 292 TestCase.assertEquals(f4, o.f4); 293 TestCase.assertEquals(f5, o.f5); 294 TestCase.assertEquals(f6, o.f6); 295 TestCase.assertEquals(f7, o.f7); 296 TestCase.assertEquals(f8, o.f8); 297 TestCase.assertEquals(f9, o.f9); 298 //TestCase.assertEquals(f10, o.f10); 299 TestCase.assertEquals(f11, o.f11); 300 TestCase.assertEquals(f12, o.f12); 301 TestCase.assertEquals(f13, o.f13); 302 TestCase.assertEquals(f14, o.f14); 303 TestCase.assertEquals(f15, o.f15); 304 TestCase.assertEquals(f16, o.f16); 305 TestCase.assertEquals(f17, o.f17); 306 TestCase.assertEquals(f18, o.f18); 307 TestCase.assertEquals(f19, o.f19); 308 } 309 } 310 311 public void testArrayTypes() 312 throws IOException, DatabaseException { 313 314 open(); 315 316 checkEntity(ArrayTypes.class, new ArrayTypes()); 317 318 checkMetadata(ArrayTypes.class.getName(), new String[][] { 319 {"id", "int"}, 320 {"f0", boolean[].class.getName()}, 321 {"f1", char[].class.getName()}, 322 {"f2", byte[].class.getName()}, 323 {"f3", short[].class.getName()}, 324 {"f4", int[].class.getName()}, 325 {"f5", long[].class.getName()}, 326 {"f6", float[].class.getName()}, 327 {"f7", double[].class.getName()}, 328 {"f8", String[].class.getName()}, 329 {"f9", Address[].class.getName()}, 330 {"f10", boolean[][][].class.getName()}, 331 {"f11", String[][][].class.getName()}, 332 }, 333 0 /*priKeyIndex*/, null); 334 335 close(); 336 } 337 338 @Entity 339 static class ArrayTypes implements MyEntity { 340 341 @PrimaryKey 342 private int id = 1; 343 private boolean[] f0 = {false, true}; 344 private char[] f1 = {'a', 'b'}; 345 private byte[] f2 = {1, 2}; 346 private short[] f3 = {1, 2}; 347 private int[] f4 = {1, 2}; 348 private long[] f5 = {1, 2}; 349 private float[] f6 = {1.1f, 2.2f}; 350 private double[] f7 = {1.1, 2,2}; 351 private String[] f8 = {"xxx", null, "yyy"}; 352 private Address[] f9 = {new Address("city", "state", 123), 353 null, 354 new Address("x", "y", 444)}; 355 private boolean[][][] f10 = 356 { 357 { 358 {false, true}, 359 {false, true}, 360 }, 361 null, 362 { 363 {false, true}, 364 {false, true}, 365 }, 366 }; 367 private String[][][] f11 = 368 { 369 { 370 {"xxx", null, "yyy"}, 371 null, 372 {"xxx", null, "yyy"}, 373 }, 374 null, 375 { 376 {"xxx", null, "yyy"}, 377 null, 378 {"xxx", null, "yyy"}, 379 }, 380 }; 381 382 ArrayTypes() { } 383 384 public Object getPriKeyObject() { 385 return id; 386 } 387 388 public void validate(Object other) { 389 ArrayTypes o = (ArrayTypes) other; 390 TestCase.assertEquals(id, o.id); 391 TestCase.assertTrue(Arrays.equals(f0, o.f0)); 392 TestCase.assertTrue(Arrays.equals(f1, o.f1)); 393 TestCase.assertTrue(Arrays.equals(f2, o.f2)); 394 TestCase.assertTrue(Arrays.equals(f3, o.f3)); 395 TestCase.assertTrue(Arrays.equals(f4, o.f4)); 396 TestCase.assertTrue(Arrays.equals(f5, o.f5)); 397 TestCase.assertTrue(Arrays.equals(f6, o.f6)); 398 TestCase.assertTrue(Arrays.equals(f7, o.f7)); 399 TestCase.assertTrue(Arrays.equals(f8, o.f8)); 400 TestCase.assertTrue(Arrays.deepEquals(f9, o.f9)); 401 TestCase.assertTrue(Arrays.deepEquals(f10, o.f10)); 402 TestCase.assertTrue(Arrays.deepEquals(f11, o.f11)); 403 } 404 } 405 406 public void testEnumTypes() 407 throws IOException, DatabaseException { 408 409 open(); 410 411 checkEntity(EnumTypes.class, new EnumTypes()); 412 413 checkMetadata(EnumTypes.class.getName(), new String[][] { 414 {"f0", "int"}, 415 {"f1", Thread.State.class.getName()}, 416 {"f2", EnumTypes.MyEnum.class.getName()}, 417 {"f3", Object.class.getName()}, 418 }, 419 0 /*priKeyIndex*/, null); 420 421 close(); 422 } 423 424 @Entity 425 static class EnumTypes implements MyEntity { 426 427 private static enum MyEnum { ONE, TWO }; 428 429 @PrimaryKey 430 private int f0 = 1; 431 private Thread.State f1 = Thread.State.RUNNABLE; 432 private MyEnum f2 = MyEnum.ONE; 433 private Object f3 = MyEnum.TWO; 434 435 EnumTypes() { } 436 437 public Object getPriKeyObject() { 438 return f0; 439 } 440 441 public void validate(Object other) { 442 EnumTypes o = (EnumTypes) other; 443 TestCase.assertEquals(f0, o.f0); 444 TestCase.assertSame(f1, o.f1); 445 TestCase.assertSame(f2, o.f2); 446 TestCase.assertSame(f3, o.f3); 447 } 448 } 449 450 public void testProxyTypes() 451 throws IOException, DatabaseException { 452 453 open(); 454 455 checkEntity(ProxyTypes.class, new ProxyTypes()); 456 457 checkMetadata(ProxyTypes.class.getName(), new String[][] { 458 {"f0", "int"}, 459 {"f1", Locale.class.getName()}, 460 {"f2", Set.class.getName()}, 461 {"f3", Set.class.getName()}, 462 {"f4", Object.class.getName()}, 463 {"f5", HashMap.class.getName()}, 464 {"f6", TreeMap.class.getName()}, 465 {"f7", List.class.getName()}, 466 {"f8", LinkedList.class.getName()}, 467 {"f9", LocalizedText.class.getName()}, 468 }, 469 0 /*priKeyIndex*/, null); 470 471 close(); 472 } 473 474 @Entity 475 static class ProxyTypes implements MyEntity { 476 477 @PrimaryKey 478 private int f0 = 1; 479 private Locale f1 = Locale.getDefault(); 480 private Set<Integer> f2 = new HashSet<Integer>(); 481 private Set<Integer> f3 = new TreeSet<Integer>(); 482 private Object f4 = new HashSet<Address>(); 483 private HashMap<String,Integer> f5 = new HashMap<String,Integer>(); 484 private TreeMap<String,Address> f6 = new TreeMap<String,Address>(); 485 private List<Integer> f7 = new ArrayList<Integer>(); 486 private LinkedList<Integer> f8 = new LinkedList<Integer>(); 487 private LocalizedText f9 = new LocalizedText(f1, "xyz"); 488 489 ProxyTypes() { 490 f2.add(123); 491 f2.add(456); 492 f3.add(456); 493 f3.add(123); 494 HashSet<Address> s = (HashSet) f4; 495 s.add(new Address("city", "state", 11111)); 496 s.add(new Address("city2", "state2", 22222)); 497 s.add(new Address("city3", "state3", 33333)); 498 f5.put("one", 111); 499 f5.put("two", 222); 500 f5.put("three", 333); 501 f6.put("one", new Address("city", "state", 11111)); 502 f6.put("two", new Address("city2", "state2", 22222)); 503 f6.put("three", new Address("city3", "state3", 33333)); 504 f7.add(123); 505 f7.add(456); 506 f8.add(123); 507 f8.add(456); 508 } 509 510 public Object getPriKeyObject() { 511 return f0; 512 } 513 514 public void validate(Object other) { 515 ProxyTypes o = (ProxyTypes) other; 516 TestCase.assertEquals(f0, o.f0); 517 TestCase.assertEquals(f1, o.f1); 518 TestCase.assertEquals(f2, o.f2); 519 TestCase.assertEquals(f3, o.f3); 520 TestCase.assertEquals(f4, o.f4); 521 TestCase.assertEquals(f5, o.f5); 522 TestCase.assertEquals(f6, o.f6); 523 TestCase.assertEquals(f7, o.f7); 524 TestCase.assertEquals(f8, o.f8); 525 TestCase.assertEquals(f9, o.f9); 526 } 527 } 528 529 @Persistent(proxyFor=Locale.class) 530 static class LocaleProxy implements PersistentProxy<Locale> { 531 532 String language; 533 String country; 534 String variant; 535 536 private LocaleProxy() {} 537 538 public void initializeProxy(Locale object) { 539 language = object.getLanguage(); 540 country = object.getCountry(); 541 variant = object.getVariant(); 542 } 543 544 public Locale convertProxy() { 545 return new Locale(language, country, variant); 546 } 547 } 548 549 static class LocalizedText { 550 551 Locale locale; 552 String text; 553 554 LocalizedText(Locale locale, String text) { 555 this.locale = locale; 556 this.text = text; 557 } 558 559 @Override 560 public boolean equals(Object other) { 561 LocalizedText o = (LocalizedText) other; 562 return text.equals(o.text) && 563 locale.equals(o.locale); 564 } 565 } 566 567 @Persistent(proxyFor=LocalizedText.class) 568 static class LocalizedTextProxy implements PersistentProxy<LocalizedText> { 569 570 Locale locale; 571 String text; 572 573 private LocalizedTextProxy() {} 574 575 public void initializeProxy(LocalizedText object) { 576 locale = object.locale; 577 text = object.text; 578 } 579 580 public LocalizedText convertProxy() { 581 return new LocalizedText(locale, text); 582 } 583 } 584 585 public void testEmbedded() 586 throws IOException, DatabaseException { 587 588 open(); 589 590 Address a1 = new Address("city", "state", 123); 591 Address a2 = new Address("Wikieup", "AZ", 85360); 592 593 checkEntity(Embedded.class, 594 new Embedded("x", a1, a2)); 595 checkEntity(Embedded.class, 596 new Embedded("y", a1, null)); 597 checkEntity(Embedded.class, 598 new Embedded("", a2, a2)); 599 600 checkMetadata(Embedded.class.getName(), new String[][] { 601 {"id", "java.lang.String"}, 602 {"idShadow", "java.lang.String"}, 603 {"one", Address.class.getName()}, 604 {"two", Address.class.getName()}, 605 }, 606 0 /*priKeyIndex*/, null); 607 608 checkMetadata(Address.class.getName(), new String[][] { 609 {"street", "java.lang.String"}, 610 {"city", "java.lang.String"}, 611 {"zip", "int"}, 612 }, 613 -1 /*priKeyIndex*/, null); 614 615 close(); 616 } 617 618 @Entity 619 static class Embedded implements MyEntity { 620 621 @PrimaryKey 622 private String id; 623 private String idShadow; 624 private Address one; 625 private Address two; 626 627 private Embedded() { } 628 629 private Embedded(String id, Address one, Address two) { 630 this.id = id; 631 idShadow = id; 632 this.one = one; 633 this.two = two; 634 } 635 636 public Object getPriKeyObject() { 637 return id; 638 } 639 640 public void validate(Object other) { 641 Embedded o = (Embedded) other; 642 TestCase.assertEquals(id, o.id); 643 if (one != null) { 644 one.validate(o.one); 645 } else { 646 assertNull(o.one); 647 } 648 if (two != null) { 649 two.validate(o.two); 650 } else { 651 assertNull(o.two); 652 } 653 TestCase.assertSame(o.id, o.idShadow); 654 if (one == two) { 655 TestCase.assertSame(o.one, o.two); 656 } 657 } 658 659 @Override 660 public String toString() { 661 return "" + id + ' ' + one + ' ' + two; 662 } 663 } 664 665 @Persistent 666 static class Address { 667 668 private String street; 669 private String city; 670 private int zip; 671 672 private Address() {} 673 674 Address(String street, String city, int zip) { 675 this.street = street; 676 this.city = city; 677 this.zip = zip; 678 } 679 680 void validate(Address o) { 681 TestCase.assertTrue(nullOrEqual(street, o.street)); 682 TestCase.assertTrue(nullOrEqual(city, o.city)); 683 TestCase.assertEquals(zip, o.zip); 684 } 685 686 @Override 687 public String toString() { 688 return "" + street + ' ' + city + ' ' + zip; 689 } 690 691 @Override 692 public boolean equals(Object other) { 693 if (other == null) { 694 return false; 695 } 696 Address o = (Address) other; 697 return nullOrEqual(street, o.street) && 698 nullOrEqual(city, o.city) && 699 nullOrEqual(zip, o.zip); 700 } 701 702 @Override 703 public int hashCode() { 704 return zip; 705 } 706 } 707 708 public void testSubclass() 709 throws IOException, DatabaseException { 710 711 open(); 712 713 checkEntity(Basic.class, 714 new Subclass(-1, "xxx", -2, "xxx", "xxx", true)); 715 716 checkMetadata(Basic.class.getName(), new String[][] { 717 {"id", "long"}, 718 {"one", "java.lang.String"}, 719 {"two", "double"}, 720 {"three", "java.lang.String"}, 721 }, 722 0 /*priKeyIndex*/, null); 723 checkMetadata(Subclass.class.getName(), new String[][] { 724 {"one", "java.lang.String"}, 725 {"two", "boolean"}, 726 }, 727 -1 /*priKeyIndex*/, Basic.class.getName()); 728 729 close(); 730 } 731 732 @Persistent 733 static class Subclass extends Basic { 734 735 private String one; 736 private boolean two; 737 738 private Subclass() { 739 } 740 741 private Subclass(long id, String one, double two, String three, 742 String subOne, boolean subTwo) { 743 super(id, one, two, three); 744 this.one = subOne; 745 this.two = subTwo; 746 } 747 748 public void validate(Object other) { 749 super.validate(other); 750 Subclass o = (Subclass) other; 751 TestCase.assertTrue(nullOrEqual(one, o.one)); 752 TestCase.assertEquals(two, o.two); 753 if (one == getBasicOne()) { 754 TestCase.assertSame(o.one, o.getBasicOne()); 755 } 756 } 757 } 758 759 public void testSuperclass() 760 throws IOException, DatabaseException { 761 762 open(); 763 764 checkEntity(UseSuperclass.class, 765 new UseSuperclass(33, "xxx")); 766 767 checkMetadata(Superclass.class.getName(), new String[][] { 768 {"id", "int"}, 769 {"one", "java.lang.String"}, 770 }, 771 0 /*priKeyIndex*/, null); 772 checkMetadata(UseSuperclass.class.getName(), new String[][] { 773 }, 774 -1 /*priKeyIndex*/, Superclass.class.getName()); 775 776 close(); 777 } 778 779 @Persistent 780 static class Superclass implements MyEntity { 781 782 @PrimaryKey 783 private int id; 784 private String one; 785 786 private Superclass() { } 787 788 private Superclass(int id, String one) { 789 this.id = id; 790 this.one = one; 791 } 792 793 public Object getPriKeyObject() { 794 return id; 795 } 796 797 public void validate(Object other) { 798 Superclass o = (Superclass) other; 799 TestCase.assertEquals(id, o.id); 800 TestCase.assertTrue(nullOrEqual(one, o.one)); 801 } 802 } 803 804 @Entity 805 static class UseSuperclass extends Superclass { 806 807 private UseSuperclass() { } 808 809 private UseSuperclass(int id, String one) { 810 super(id, one); 811 } 812 } 813 814 public void testAbstract() 815 throws IOException, DatabaseException { 816 817 open(); 818 819 checkEntity(EntityUseAbstract.class, 820 new EntityUseAbstract(33, "xxx")); 821 822 checkMetadata(Abstract.class.getName(), new String[][] { 823 {"one", "java.lang.String"}, 824 }, 825 -1 /*priKeyIndex*/, null); 826 checkMetadata(EmbeddedUseAbstract.class.getName(), new String[][] { 827 {"two", "java.lang.String"}, 828 }, 829 -1 /*priKeyIndex*/, Abstract.class.getName()); 830 checkMetadata(EntityUseAbstract.class.getName(), new String[][] { 831 {"id", "int"}, 832 {"f1", EmbeddedUseAbstract.class.getName()}, 833 {"f2", Abstract.class.getName()}, 834 {"f3", Object.class.getName()}, 835 {"f4", Interface.class.getName()}, 836 {"a1", EmbeddedUseAbstract[].class.getName()}, 837 {"a2", Abstract[].class.getName()}, 838 {"a3", Abstract[].class.getName()}, 839 {"a4", Object[].class.getName()}, 840 {"a5", Interface[].class.getName()}, 841 {"a6", Interface[].class.getName()}, 842 {"a7", Interface[].class.getName()}, 843 }, 844 0 /*priKeyIndex*/, Abstract.class.getName()); 845 846 close(); 847 } 848 849 @Persistent 850 static abstract class Abstract implements Interface { 851 852 String one; 853 854 private Abstract() { } 855 856 private Abstract(String one) { 857 this.one = one; 858 } 859 860 public void validate(Object other) { 861 Abstract o = (Abstract) other; 862 TestCase.assertTrue(nullOrEqual(one, o.one)); 863 } 864 865 @Override 866 public boolean equals(Object other) { 867 Abstract o = (Abstract) other; 868 return nullOrEqual(one, o.one); 869 } 870 } 871 872 interface Interface { 873 void validate(Object other); 874 } 875 876 @Persistent 877 static class EmbeddedUseAbstract extends Abstract { 878 879 private String two; 880 881 private EmbeddedUseAbstract() { } 882 883 private EmbeddedUseAbstract(String one, String two) { 884 super(one); 885 this.two = two; 886 } 887 888 @Override 889 public void validate(Object other) { 890 super.validate(other); 891 EmbeddedUseAbstract o = (EmbeddedUseAbstract) other; 892 TestCase.assertTrue(nullOrEqual(two, o.two)); 893 } 894 895 @Override 896 public boolean equals(Object other) { 897 if (!super.equals(other)) { 898 return false; 899 } 900 EmbeddedUseAbstract o = (EmbeddedUseAbstract) other; 901 return nullOrEqual(two, o.two); 902 } 903 } 904 905 @Entity 906 static class EntityUseAbstract extends Abstract implements MyEntity { 907 908 @PrimaryKey 909 private int id; 910 911 private EmbeddedUseAbstract f1; 912 private Abstract f2; 913 private Object f3; 914 private Interface f4; 915 private EmbeddedUseAbstract[] a1; 916 private Abstract[] a2; 917 private Abstract[] a3; 918 private Object[] a4; 919 private Interface[] a5; 920 private Interface[] a6; 921 private Interface[] a7; 922 923 private EntityUseAbstract() { } 924 925 private EntityUseAbstract(int id, String one) { 926 super(one); 927 this.id = id; 928 f1 = new EmbeddedUseAbstract(one, one); 929 f2 = new EmbeddedUseAbstract(one + "x", one + "y"); 930 f3 = new EmbeddedUseAbstract(null, null); 931 f4 = new EmbeddedUseAbstract(null, null); 932 a1 = new EmbeddedUseAbstract[3]; 933 a2 = new EmbeddedUseAbstract[3]; 934 a3 = new Abstract[3]; 935 a4 = new Object[3]; 936 a5 = new EmbeddedUseAbstract[3]; 937 a6 = new Abstract[3]; 938 a7 = new Interface[3]; 939 for (int i = 0; i < 3; i += 1) { 940 a1[i] = new EmbeddedUseAbstract("1" + i, null); 941 a2[i] = new EmbeddedUseAbstract("2" + i, null); 942 a3[i] = new EmbeddedUseAbstract("3" + i, null); 943 a4[i] = new EmbeddedUseAbstract("4" + i, null); 944 a5[i] = new EmbeddedUseAbstract("5" + i, null); 945 a6[i] = new EmbeddedUseAbstract("6" + i, null); 946 a7[i] = new EmbeddedUseAbstract("7" + i, null); 947 } 948 } 949 950 public Object getPriKeyObject() { 951 return id; 952 } 953 954 @Override 955 public void validate(Object other) { 956 super.validate(other); 957 EntityUseAbstract o = (EntityUseAbstract) other; 958 TestCase.assertEquals(id, o.id); 959 f1.validate(o.f1); 960 assertSame(o.one, o.f1.one); 961 assertSame(o.f1.one, o.f1.two); 962 f2.validate(o.f2); 963 ((Abstract) f3).validate(o.f3); 964 f4.validate(o.f4); 965 assertTrue(arrayToString(a1) + ' ' + arrayToString(o.a1), 966 Arrays.equals(a1, o.a1)); 967 assertTrue(Arrays.equals(a2, o.a2)); 968 assertTrue(Arrays.equals(a3, o.a3)); 969 assertTrue(Arrays.equals(a4, o.a4)); 970 assertTrue(Arrays.equals(a5, o.a5)); 971 assertTrue(Arrays.equals(a6, o.a6)); 972 assertTrue(Arrays.equals(a7, o.a7)); 973 assertSame(EmbeddedUseAbstract.class, f2.getClass()); 974 assertSame(EmbeddedUseAbstract.class, f3.getClass()); 975 assertSame(EmbeddedUseAbstract[].class, a1.getClass()); 976 assertSame(EmbeddedUseAbstract[].class, a2.getClass()); 977 assertSame(Abstract[].class, a3.getClass()); 978 assertSame(Object[].class, a4.getClass()); 979 assertSame(EmbeddedUseAbstract[].class, a5.getClass()); 980 assertSame(Abstract[].class, a6.getClass()); 981 assertSame(Interface[].class, a7.getClass()); 982 } 983 } 984 985 public void testCompositeKey() 986 throws IOException, DatabaseException { 987 988 open(); 989 990 CompositeKey key = 991 new CompositeKey(123, 456L, "xyz", BigInteger.valueOf(789)); 992 checkEntity(UseCompositeKey.class, 993 new UseCompositeKey(key, "one")); 994 995 checkMetadata(UseCompositeKey.class.getName(), new String[][] { 996 {"key", CompositeKey.class.getName()}, 997 {"one", "java.lang.String"}, 998 }, 999 0 /*priKeyIndex*/, null); 1000 1001 checkMetadata(CompositeKey.class.getName(), new String[][] { 1002 {"f1", "int"}, 1003 {"f2", "java.lang.Long"}, 1004 {"f3", "java.lang.String"}, 1005 {"f4", "java.math.BigInteger"}, 1006 }, 1007 -1 /*priKeyIndex*/, null); 1008 1009 close(); 1010 } 1011 1012 @Persistent 1013 static class CompositeKey { 1014 @KeyField(3) 1015 private int f1; 1016 @KeyField(2) 1017 private Long f2; 1018 @KeyField(1) 1019 private String f3; 1020 @KeyField(4) 1021 private BigInteger f4; 1022 1023 private CompositeKey() {} 1024 1025 CompositeKey(int f1, Long f2, String f3, BigInteger f4) { 1026 this.f1 = f1; 1027 this.f2 = f2; 1028 this.f3 = f3; 1029 this.f4 = f4; 1030 } 1031 1032 void validate(CompositeKey o) { 1033 TestCase.assertEquals(f1, o.f1); 1034 TestCase.assertTrue(nullOrEqual(f2, o.f2)); 1035 TestCase.assertTrue(nullOrEqual(f3, o.f3)); 1036 TestCase.assertTrue(nullOrEqual(f4, o.f4)); 1037 } 1038 1039 @Override 1040 public boolean equals(Object other) { 1041 CompositeKey o = (CompositeKey) other; 1042 return f1 == o.f1 && 1043 nullOrEqual(f2, o.f2) && 1044 nullOrEqual(f3, o.f3) && 1045 nullOrEqual(f4, o.f4); 1046 } 1047 1048 @Override 1049 public int hashCode() { 1050 return f1; 1051 } 1052 1053 @Override 1054 public String toString() { 1055 return "" + f1 + ' ' + f2 + ' ' + f3 + ' ' + f4; 1056 } 1057 } 1058 1059 @Entity 1060 static class UseCompositeKey implements MyEntity { 1061 1062 @PrimaryKey 1063 private CompositeKey key; 1064 private String one; 1065 1066 private UseCompositeKey() { } 1067 1068 private UseCompositeKey(CompositeKey key, String one) { 1069 this.key = key; 1070 this.one = one; 1071 } 1072 1073 public Object getPriKeyObject() { 1074 return key; 1075 } 1076 1077 public void validate(Object other) { 1078 UseCompositeKey o = (UseCompositeKey) other; 1079 TestCase.assertNotNull(key); 1080 TestCase.assertNotNull(o.key); 1081 key.validate(o.key); 1082 TestCase.assertTrue(nullOrEqual(one, o.one)); 1083 } 1084 } 1085 1086 public void testComparableKey() 1087 throws IOException, DatabaseException { 1088 1089 open(); 1090 1091 ComparableKey key = new ComparableKey(123, 456); 1092 checkEntity(UseComparableKey.class, 1093 new UseComparableKey(key, "one")); 1094 1095 checkMetadata(UseComparableKey.class.getName(), new String[][] { 1096 {"key", ComparableKey.class.getName()}, 1097 {"one", "java.lang.String"}, 1098 }, 1099 0 /*priKeyIndex*/, null); 1100 1101 checkMetadata(ComparableKey.class.getName(), new String[][] { 1102 {"f1", "int"}, 1103 {"f2", "int"}, 1104 }, 1105 -1 /*priKeyIndex*/, null); 1106 1107 ClassMetadata classMeta = 1108 model.getClassMetadata(UseComparableKey.class.getName()); 1109 assertNotNull(classMeta); 1110 1111 PersistKeyBinding binding = new PersistKeyBinding 1112 (catalog, ComparableKey.class.getName(), false); 1113 1114 PersistComparator comparator = new PersistComparator 1115 (ComparableKey.class.getName(), 1116 classMeta.getCompositeKeyFields(), 1117 binding); 1118 1119 compareKeys(comparator, binding, new ComparableKey(1, 1), 1120 new ComparableKey(1, 1), 0); 1121 compareKeys(comparator, binding, new ComparableKey(1, 2), 1122 new ComparableKey(1, 1), -1); 1123 compareKeys(comparator, binding, new ComparableKey(2, 1), 1124 new ComparableKey(1, 1), -1); 1125 compareKeys(comparator, binding, new ComparableKey(2, 1), 1126 new ComparableKey(3, 1), 1); 1127 1128 close(); 1129 } 1130 1131 private void compareKeys(Comparator<Object> comparator, 1132 EntryBinding binding, 1133 Object key1, 1134 Object key2, 1135 int expectResult) { 1136 DatabaseEntry entry1 = new DatabaseEntry(); 1137 DatabaseEntry entry2 = new DatabaseEntry(); 1138 binding.objectToEntry(key1, entry1); 1139 binding.objectToEntry(key2, entry2); 1140 int result = comparator.compare(entry1.getData(), entry2.getData()); 1141 assertEquals(expectResult, result); 1142 } 1143 1144 @Persistent 1145 static class ComparableKey implements Comparable<ComparableKey> { 1146 @KeyField(2) 1147 private int f1; 1148 @KeyField(1) 1149 private int f2; 1150 1151 private ComparableKey() {} 1152 1153 ComparableKey(int f1, int f2) { 1154 this.f1 = f1; 1155 this.f2 = f2; 1156 } 1157 1158 void validate(ComparableKey o) { 1159 TestCase.assertEquals(f1, o.f1); 1160 TestCase.assertEquals(f2, o.f2); 1161 } 1162 1163 @Override 1164 public boolean equals(Object other) { 1165 ComparableKey o = (ComparableKey) other; 1166 return f1 == o.f1 && f2 == o.f2; 1167 } 1168 1169 @Override 1170 public int hashCode() { 1171 return f1 + f2; 1172 } 1173 1174 @Override 1175 public String toString() { 1176 return "" + f1 + ' ' + f2; 1177 } 1178 1179 /** Compare f1 then f2, in reverse integer order. */ 1180 public int compareTo(ComparableKey o) { 1181 if (f1 != o.f1) { 1182 return o.f1 - f1; 1183 } else { 1184 return o.f2 - f2; 1185 } 1186 } 1187 } 1188 1189 @Entity 1190 static class UseComparableKey implements MyEntity { 1191 1192 @PrimaryKey 1193 private ComparableKey key; 1194 private String one; 1195 1196 private UseComparableKey() { } 1197 1198 private UseComparableKey(ComparableKey key, String one) { 1199 this.key = key; 1200 this.one = one; 1201 } 1202 1203 public Object getPriKeyObject() { 1204 return key; 1205 } 1206 1207 public void validate(Object other) { 1208 UseComparableKey o = (UseComparableKey) other; 1209 TestCase.assertNotNull(key); 1210 TestCase.assertNotNull(o.key); 1211 key.validate(o.key); 1212 TestCase.assertTrue(nullOrEqual(one, o.one)); 1213 } 1214 } 1215 1216 public void testSecKeys() 1217 throws IOException, DatabaseException { 1218 1219 open(); 1220 1221 SecKeys obj = new SecKeys(); 1222 checkEntity(SecKeys.class, obj); 1223 1224 checkMetadata(SecKeys.class.getName(), new String[][] { 1225 {"id", "long"}, 1226 {"f0", "boolean"}, 1227 {"g0", "boolean"}, 1228 {"f1", "char"}, 1229 {"g1", "char"}, 1230 {"f2", "byte"}, 1231 {"g2", "byte"}, 1232 {"f3", "short"}, 1233 {"g3", "short"}, 1234 {"f4", "int"}, 1235 {"g4", "int"}, 1236 {"f5", "long"}, 1237 {"g5", "long"}, 1238 {"f6", "float"}, 1239 {"g6", "float"}, 1240 {"f7", "double"}, 1241 {"g7", "double"}, 1242 {"f8", "java.lang.String"}, 1243 {"g8", "java.lang.String"}, 1244 {"f9", "java.math.BigInteger"}, 1245 {"g9", "java.math.BigInteger"}, 1246 //{"f10", "java.math.BigDecimal"}, 1247 //{"g10", "java.math.BigDecimal"}, 1248 {"f11", "java.util.Date"}, 1249 {"g11", "java.util.Date"}, 1250 {"f12", "java.lang.Boolean"}, 1251 {"g12", "java.lang.Boolean"}, 1252 {"f13", "java.lang.Character"}, 1253 {"g13", "java.lang.Character"}, 1254 {"f14", "java.lang.Byte"}, 1255 {"g14", "java.lang.Byte"}, 1256 {"f15", "java.lang.Short"}, 1257 {"g15", "java.lang.Short"}, 1258 {"f16", "java.lang.Integer"}, 1259 {"g16", "java.lang.Integer"}, 1260 {"f17", "java.lang.Long"}, 1261 {"g17", "java.lang.Long"}, 1262 {"f18", "java.lang.Float"}, 1263 {"g18", "java.lang.Float"}, 1264 {"f19", "java.lang.Double"}, 1265 {"g19", "java.lang.Double"}, 1266 {"f20", CompositeKey.class.getName()}, 1267 {"g20", CompositeKey.class.getName()}, 1268 {"f21", int[].class.getName()}, 1269 {"g21", int[].class.getName()}, 1270 {"f22", Integer[].class.getName()}, 1271 {"g22", Integer[].class.getName()}, 1272 {"f23", Set.class.getName()}, 1273 {"g23", Set.class.getName()}, 1274 {"f24", CompositeKey[].class.getName()}, 1275 {"g24", CompositeKey[].class.getName()}, 1276 {"f25", Set.class.getName()}, 1277 {"g25", Set.class.getName()}, 1278 {"f31", "java.util.Date"}, 1279 {"f32", "java.lang.Boolean"}, 1280 {"f33", "java.lang.Character"}, 1281 {"f34", "java.lang.Byte"}, 1282 {"f35", "java.lang.Short"}, 1283 {"f36", "java.lang.Integer"}, 1284 {"f37", "java.lang.Long"}, 1285 {"f38", "java.lang.Float"}, 1286 {"f39", "java.lang.Double"}, 1287 {"f40", CompositeKey.class.getName()}, 1288 }, 1289 0 /*priKeyIndex*/, null); 1290 1291 checkSecKey(obj, "f0", obj.f0, Boolean.class); 1292 checkSecKey(obj, "f1", obj.f1, Character.class); 1293 checkSecKey(obj, "f2", obj.f2, Byte.class); 1294 checkSecKey(obj, "f3", obj.f3, Short.class); 1295 checkSecKey(obj, "f4", obj.f4, Integer.class); 1296 checkSecKey(obj, "f5", obj.f5, Long.class); 1297 checkSecKey(obj, "f6", obj.f6, Float.class); 1298 checkSecKey(obj, "f7", obj.f7, Double.class); 1299 checkSecKey(obj, "f8", obj.f8, String.class); 1300 checkSecKey(obj, "f9", obj.f9, BigInteger.class); 1301 //checkSecKey(obj, "f10", obj.f10, BigDecimal.class); 1302 checkSecKey(obj, "f11", obj.f11, Date.class); 1303 checkSecKey(obj, "f12", obj.f12, Boolean.class); 1304 checkSecKey(obj, "f13", obj.f13, Character.class); 1305 checkSecKey(obj, "f14", obj.f14, Byte.class); 1306 checkSecKey(obj, "f15", obj.f15, Short.class); 1307 checkSecKey(obj, "f16", obj.f16, Integer.class); 1308 checkSecKey(obj, "f17", obj.f17, Long.class); 1309 checkSecKey(obj, "f18", obj.f18, Float.class); 1310 checkSecKey(obj, "f19", obj.f19, Double.class); 1311 checkSecKey(obj, "f20", obj.f20, CompositeKey.class); 1312 1313 checkSecMultiKey(obj, "f21", toSet(obj.f21), Integer.class); 1314 checkSecMultiKey(obj, "f22", toSet(obj.f22), Integer.class); 1315 checkSecMultiKey(obj, "f23", toSet(obj.f23), Integer.class); 1316 checkSecMultiKey(obj, "f24", toSet(obj.f24), CompositeKey.class); 1317 checkSecMultiKey(obj, "f25", toSet(obj.f25), CompositeKey.class); 1318 1319 nullifySecKey(obj, "f8", obj.f8, String.class); 1320 nullifySecKey(obj, "f9", obj.f9, BigInteger.class); 1321 //nullifySecKey(obj, "f10", obj.f10, BigDecimal.class); 1322 nullifySecKey(obj, "f11", obj.f11, Date.class); 1323 nullifySecKey(obj, "f12", obj.f12, Boolean.class); 1324 nullifySecKey(obj, "f13", obj.f13, Character.class); 1325 nullifySecKey(obj, "f14", obj.f14, Byte.class); 1326 nullifySecKey(obj, "f15", obj.f15, Short.class); 1327 nullifySecKey(obj, "f16", obj.f16, Integer.class); 1328 nullifySecKey(obj, "f17", obj.f17, Long.class); 1329 nullifySecKey(obj, "f18", obj.f18, Float.class); 1330 nullifySecKey(obj, "f19", obj.f19, Double.class); 1331 nullifySecKey(obj, "f20", obj.f20, CompositeKey.class); 1332 1333 nullifySecMultiKey(obj, "f21", obj.f21, Integer.class); 1334 nullifySecMultiKey(obj, "f22", obj.f22, Integer.class); 1335 nullifySecMultiKey(obj, "f23", obj.f23, Integer.class); 1336 nullifySecMultiKey(obj, "f24", obj.f24, CompositeKey.class); 1337 nullifySecMultiKey(obj, "f25", obj.f25, CompositeKey.class); 1338 1339 nullifySecKey(obj, "f31", obj.f31, Date.class); 1340 nullifySecKey(obj, "f32", obj.f32, Boolean.class); 1341 nullifySecKey(obj, "f33", obj.f33, Character.class); 1342 nullifySecKey(obj, "f34", obj.f34, Byte.class); 1343 nullifySecKey(obj, "f35", obj.f35, Short.class); 1344 nullifySecKey(obj, "f36", obj.f36, Integer.class); 1345 nullifySecKey(obj, "f37", obj.f37, Long.class); 1346 nullifySecKey(obj, "f38", obj.f38, Float.class); 1347 nullifySecKey(obj, "f39", obj.f39, Double.class); 1348 nullifySecKey(obj, "f40", obj.f40, CompositeKey.class); 1349 1350 close(); 1351 } 1352 1353 static Set toSet(int[] a) { 1354 Set set = new HashSet(); 1355 for (int i : a) { 1356 set.add(i); 1357 } 1358 return set; 1359 } 1360 1361 static Set toSet(Object[] a) { 1362 return new HashSet(Arrays.asList(a)); 1363 } 1364 1365 static Set toSet(Set s) { 1366 return s; 1367 } 1368 1369 @Entity 1370 static class SecKeys implements MyEntity { 1371 1372 @PrimaryKey 1373 long id; 1374 1375 @SecondaryKey(relate=MANY_TO_ONE) 1376 private boolean f0 = false; 1377 private boolean g0 = false; 1378 1379 @SecondaryKey(relate=MANY_TO_ONE) 1380 private char f1 = '1'; 1381 private char g1 = '1'; 1382 1383 @SecondaryKey(relate=MANY_TO_ONE) 1384 private byte f2 = 2; 1385 private byte g2 = 2; 1386 1387 @SecondaryKey(relate=MANY_TO_ONE) 1388 private short f3 = 3; 1389 private short g3 = 3; 1390 1391 @SecondaryKey(relate=MANY_TO_ONE) 1392 private int f4 = 4; 1393 private int g4 = 4; 1394 1395 @SecondaryKey(relate=MANY_TO_ONE) 1396 private long f5 = 5; 1397 private long g5 = 5; 1398 1399 @SecondaryKey(relate=MANY_TO_ONE) 1400 private float f6 = 6.6f; 1401 private float g6 = 6.6f; 1402 1403 @SecondaryKey(relate=MANY_TO_ONE) 1404 private double f7 = 7.7; 1405 private double g7 = 7.7; 1406 1407 @SecondaryKey(relate=MANY_TO_ONE) 1408 private String f8 = "8"; 1409 private String g8 = "8"; 1410 1411 @SecondaryKey(relate=MANY_TO_ONE) 1412 private BigInteger f9; 1413 private BigInteger g9; 1414 1415 //@SecondaryKey(relate=MANY_TO_ONE) 1416 //private BigDecimal f10; 1417 //private BigDecimal g10; 1418 1419 @SecondaryKey(relate=MANY_TO_ONE) 1420 private Date f11 = new Date(11); 1421 private Date g11 = new Date(11); 1422 1423 @SecondaryKey(relate=MANY_TO_ONE) 1424 private Boolean f12 = true; 1425 private Boolean g12 = true; 1426 1427 @SecondaryKey(relate=MANY_TO_ONE) 1428 private Character f13 = '3'; 1429 private Character g13 = '3'; 1430 1431 @SecondaryKey(relate=MANY_TO_ONE) 1432 private Byte f14 = 14; 1433 private Byte g14 = 14; 1434 1435 @SecondaryKey(relate=MANY_TO_ONE) 1436 private Short f15 = 15; 1437 private Short g15 = 15; 1438 1439 @SecondaryKey(relate=MANY_TO_ONE) 1440 private Integer f16 = 16; 1441 private Integer g16 = 16; 1442 1443 @SecondaryKey(relate=MANY_TO_ONE) 1444 private Long f17= 17L; 1445 private Long g17= 17L; 1446 1447 @SecondaryKey(relate=MANY_TO_ONE) 1448 private Float f18 = 18.18f; 1449 private Float g18 = 18.18f; 1450 1451 @SecondaryKey(relate=MANY_TO_ONE) 1452 private Double f19 = 19.19; 1453 private Double g19 = 19.19; 1454 1455 @SecondaryKey(relate=MANY_TO_ONE) 1456 private CompositeKey f20 = 1457 new CompositeKey(20, 20L, "20", BigInteger.valueOf(20)); 1458 private CompositeKey g20 = 1459 new CompositeKey(20, 20L, "20", BigInteger.valueOf(20)); 1460 1461 private static int[] arrayOfInt = { 100, 101, 102 }; 1462 1463 private static Integer[] arrayOfInteger = { 100, 101, 102 }; 1464 1465 private static CompositeKey[] arrayOfCompositeKey = { 1466 new CompositeKey(100, 100L, "100", BigInteger.valueOf(100)), 1467 new CompositeKey(101, 101L, "101", BigInteger.valueOf(101)), 1468 new CompositeKey(102, 102L, "102", BigInteger.valueOf(102)), 1469 }; 1470 1471 @SecondaryKey(relate=ONE_TO_MANY) 1472 private int[] f21 = arrayOfInt; 1473 private int[] g21 = f21; 1474 1475 @SecondaryKey(relate=ONE_TO_MANY) 1476 private Integer[] f22 = arrayOfInteger; 1477 private Integer[] g22 = f22; 1478 1479 @SecondaryKey(relate=ONE_TO_MANY) 1480 private Set<Integer> f23 = toSet(arrayOfInteger); 1481 private Set<Integer> g23 = f23; 1482 1483 @SecondaryKey(relate=ONE_TO_MANY) 1484 private CompositeKey[] f24 = arrayOfCompositeKey; 1485 private CompositeKey[] g24 = f24; 1486 1487 @SecondaryKey(relate=ONE_TO_MANY) 1488 private Set<CompositeKey> f25 = toSet(arrayOfCompositeKey); 1489 private Set<CompositeKey> g25 = f25; 1490 1491 /* Repeated key values to test shared references. */ 1492 1493 @SecondaryKey(relate=MANY_TO_ONE) 1494 private Date f31 = f11; 1495 1496 @SecondaryKey(relate=MANY_TO_ONE) 1497 private Boolean f32 = f12; 1498 1499 @SecondaryKey(relate=MANY_TO_ONE) 1500 private Character f33 = f13; 1501 1502 @SecondaryKey(relate=MANY_TO_ONE) 1503 private Byte f34 = f14; 1504 1505 @SecondaryKey(relate=MANY_TO_ONE) 1506 private Short f35 = f15; 1507 1508 @SecondaryKey(relate=MANY_TO_ONE) 1509 private Integer f36 = f16; 1510 1511 @SecondaryKey(relate=MANY_TO_ONE) 1512 private Long f37= f17; 1513 1514 @SecondaryKey(relate=MANY_TO_ONE) 1515 private Float f38 = f18; 1516 1517 @SecondaryKey(relate=MANY_TO_ONE) 1518 private Double f39 = f19; 1519 1520 @SecondaryKey(relate=MANY_TO_ONE) 1521 private CompositeKey f40 = f20; 1522 1523 public Object getPriKeyObject() { 1524 return id; 1525 } 1526 1527 public void validate(Object other) { 1528 SecKeys o = (SecKeys) other; 1529 TestCase.assertEquals(id, o.id); 1530 1531 TestCase.assertEquals(f0, o.f0); 1532 TestCase.assertEquals(f1, o.f1); 1533 TestCase.assertEquals(f2, o.f2); 1534 TestCase.assertEquals(f3, o.f3); 1535 TestCase.assertEquals(f4, o.f4); 1536 TestCase.assertEquals(f5, o.f5); 1537 TestCase.assertEquals(f6, o.f6); 1538 TestCase.assertEquals(f7, o.f7); 1539 TestCase.assertEquals(f8, o.f8); 1540 TestCase.assertEquals(f9, o.f9); 1541 //TestCase.assertEquals(f10, o.f10); 1542 TestCase.assertEquals(f11, o.f11); 1543 TestCase.assertEquals(f12, o.f12); 1544 TestCase.assertEquals(f13, o.f13); 1545 TestCase.assertEquals(f14, o.f14); 1546 TestCase.assertEquals(f15, o.f15); 1547 TestCase.assertEquals(f16, o.f16); 1548 TestCase.assertEquals(f17, o.f17); 1549 TestCase.assertEquals(f18, o.f18); 1550 TestCase.assertEquals(f19, o.f19); 1551 TestCase.assertEquals(f20, o.f20); 1552 TestCase.assertTrue(Arrays.equals(f21, o.f21)); 1553 TestCase.assertTrue(Arrays.equals(f22, o.f22)); 1554 TestCase.assertEquals(f23, o.f23); 1555 TestCase.assertTrue(Arrays.equals(f24, o.f24)); 1556 TestCase.assertEquals(f25, o.f25); 1557 1558 TestCase.assertEquals(g0, o.g0); 1559 TestCase.assertEquals(g1, o.g1); 1560 TestCase.assertEquals(g2, o.g2); 1561 TestCase.assertEquals(g3, o.g3); 1562 TestCase.assertEquals(g4, o.g4); 1563 TestCase.assertEquals(g5, o.g5); 1564 TestCase.assertEquals(g6, o.g6); 1565 TestCase.assertEquals(g7, o.g7); 1566 TestCase.assertEquals(g8, o.g8); 1567 TestCase.assertEquals(g9, o.g9); 1568 //TestCase.assertEquals(g10, o.g10); 1569 TestCase.assertEquals(g11, o.g11); 1570 TestCase.assertEquals(g12, o.g12); 1571 TestCase.assertEquals(g13, o.g13); 1572 TestCase.assertEquals(g14, o.g14); 1573 TestCase.assertEquals(g15, o.g15); 1574 TestCase.assertEquals(g16, o.g16); 1575 TestCase.assertEquals(g17, o.g17); 1576 TestCase.assertEquals(g18, o.g18); 1577 TestCase.assertEquals(g19, o.g19); 1578 TestCase.assertEquals(g20, o.g20); 1579 TestCase.assertTrue(Arrays.equals(g21, o.g21)); 1580 TestCase.assertTrue(Arrays.equals(g22, o.g22)); 1581 TestCase.assertEquals(g23, o.g23); 1582 TestCase.assertTrue(Arrays.equals(g24, o.g24)); 1583 TestCase.assertEquals(g25, o.g25); 1584 1585 TestCase.assertEquals(f31, o.f31); 1586 TestCase.assertEquals(f32, o.f32); 1587 TestCase.assertEquals(f33, o.f33); 1588 TestCase.assertEquals(f34, o.f34); 1589 TestCase.assertEquals(f35, o.f35); 1590 TestCase.assertEquals(f36, o.f36); 1591 TestCase.assertEquals(f37, o.f37); 1592 TestCase.assertEquals(f38, o.f38); 1593 TestCase.assertEquals(f39, o.f39); 1594 TestCase.assertEquals(f40, o.f40); 1595 1596 checkSameIfNonNull(o.f31, o.f11); 1597 checkSameIfNonNull(o.f32, o.f12); 1598 checkSameIfNonNull(o.f33, o.f13); 1599 checkSameIfNonNull(o.f34, o.f14); 1600 checkSameIfNonNull(o.f35, o.f15); 1601 checkSameIfNonNull(o.f36, o.f16); 1602 checkSameIfNonNull(o.f37, o.f17); 1603 checkSameIfNonNull(o.f38, o.f18); 1604 checkSameIfNonNull(o.f39, o.f19); 1605 checkSameIfNonNull(o.f40, o.f20); 1606 } 1607 } 1608 1609 public void testSecKeyRefToPriKey() 1610 throws IOException, DatabaseException { 1611 1612 open(); 1613 1614 SecKeyRefToPriKey obj = new SecKeyRefToPriKey(); 1615 checkEntity(SecKeyRefToPriKey.class, obj); 1616 1617 checkMetadata(SecKeyRefToPriKey.class.getName(), new String[][] { 1618 {"priKey", "java.lang.String"}, 1619 {"secKey1", "java.lang.String"}, 1620 {"secKey2", String[].class.getName()}, 1621 {"secKey3", Set.class.getName()}, 1622 }, 1623 0 /*priKeyIndex*/, null); 1624 1625 checkSecKey(obj, "secKey1", obj.secKey1, String.class); 1626 checkSecMultiKey(obj, "secKey2", toSet(obj.secKey2), String.class); 1627 checkSecMultiKey(obj, "secKey3", toSet(obj.secKey3), String.class); 1628 1629 close(); 1630 } 1631 1632 @Entity 1633 static class SecKeyRefToPriKey implements MyEntity { 1634 1635 @PrimaryKey 1636 private String priKey; 1637 1638 @SecondaryKey(relate=ONE_TO_ONE) 1639 private String secKey1; 1640 1641 @SecondaryKey(relate=ONE_TO_MANY) 1642 private String[] secKey2; 1643 1644 @SecondaryKey(relate=ONE_TO_MANY) 1645 private Set<String> secKey3 = new HashSet<String>(); 1646 1647 private SecKeyRefToPriKey() { 1648 priKey = "sharedValue"; 1649 secKey1 = priKey; 1650 secKey2 = new String[] { priKey }; 1651 secKey3.add(priKey); 1652 } 1653 1654 public Object getPriKeyObject() { 1655 return priKey; 1656 } 1657 1658 public void validate(Object other) { 1659 SecKeyRefToPriKey o = (SecKeyRefToPriKey) other; 1660 TestCase.assertEquals(priKey, o.priKey); 1661 TestCase.assertNotNull(o.secKey1); 1662 TestCase.assertEquals(1, o.secKey2.length); 1663 TestCase.assertEquals(1, o.secKey3.size()); 1664 TestCase.assertSame(o.secKey1, o.priKey); 1665 TestCase.assertSame(o.secKey2[0], o.priKey); 1666 TestCase.assertSame(o.secKey3.iterator().next(), o.priKey); 1667 } 1668 } 1669 1670 public void testSecKeyInSuperclass() 1671 throws IOException, DatabaseException { 1672 1673 open(); 1674 1675 SecKeyInSuperclassEntity obj = new SecKeyInSuperclassEntity(); 1676 checkEntity(SecKeyInSuperclassEntity.class, obj); 1677 1678 checkMetadata(SecKeyInSuperclass.class.getName(), new String[][] { 1679 {"priKey", "java.lang.String"}, 1680 {"secKey1", String.class.getName()}, 1681 }, 1682 0/*priKeyIndex*/, null); 1683 1684 checkMetadata(SecKeyInSuperclassEntity.class.getName(), new String[][] { 1685 {"secKey2", "java.lang.String"}, 1686 }, 1687 -1 /*priKeyIndex*/, SecKeyInSuperclass.class.getName()); 1688 1689 checkSecKey 1690 (obj, SecKeyInSuperclassEntity.class, "secKey1", obj.secKey1, 1691 String.class); 1692 checkSecKey 1693 (obj, SecKeyInSuperclassEntity.class, "secKey2", obj.secKey2, 1694 String.class); 1695 1696 close(); 1697 } 1698 1699 @Persistent 1700 static class SecKeyInSuperclass implements MyEntity { 1701 1702 @PrimaryKey 1703 String priKey = "1"; 1704 1705 @SecondaryKey(relate=ONE_TO_ONE) 1706 String secKey1 = "1"; 1707 1708 public Object getPriKeyObject() { 1709 return priKey; 1710 } 1711 1712 public void validate(Object other) { 1713 SecKeyInSuperclass o = (SecKeyInSuperclass) other; 1714 TestCase.assertEquals(secKey1, o.secKey1); 1715 } 1716 } 1717 1718 @Entity 1719 static class SecKeyInSuperclassEntity extends SecKeyInSuperclass { 1720 1721 @SecondaryKey(relate=ONE_TO_ONE) 1722 String secKey2 = "2"; 1723 1724 public void validate(Object other) { 1725 super.validate(other); 1726 SecKeyInSuperclassEntity o = (SecKeyInSuperclassEntity) other; 1727 TestCase.assertEquals(priKey, o.priKey); 1728 TestCase.assertEquals(secKey2, o.secKey2); 1729 } 1730 } 1731 1732 public void testSecKeyInSubclass() 1733 throws IOException, DatabaseException { 1734 1735 open(); 1736 1737 SecKeyInSubclass obj = new SecKeyInSubclass(); 1738 checkEntity(SecKeyInSubclassEntity.class, obj); 1739 1740 checkMetadata(SecKeyInSubclassEntity.class.getName(), new String[][] { 1741 {"priKey", "java.lang.String"}, 1742 {"secKey1", "java.lang.String"}, 1743 }, 1744 0 /*priKeyIndex*/, null); 1745 1746 checkMetadata(SecKeyInSubclass.class.getName(), new String[][] { 1747 {"secKey2", String.class.getName()}, 1748 }, 1749 -1 /*priKeyIndex*/, 1750 SecKeyInSubclassEntity.class.getName()); 1751 1752 checkSecKey 1753 (obj, SecKeyInSubclassEntity.class, "secKey1", obj.secKey1, 1754 String.class); 1755 checkSecKey 1756 (obj, SecKeyInSubclassEntity.class, "secKey2", obj.secKey2, 1757 String.class); 1758 1759 close(); 1760 } 1761 1762 @Entity 1763 static class SecKeyInSubclassEntity implements MyEntity { 1764 1765 @PrimaryKey 1766 String priKey = "1"; 1767 1768 @SecondaryKey(relate=ONE_TO_ONE) 1769 String secKey1; 1770 1771 public Object getPriKeyObject() { 1772 return priKey; 1773 } 1774 1775 public void validate(Object other) { 1776 SecKeyInSubclassEntity o = (SecKeyInSubclassEntity) other; 1777 TestCase.assertEquals(priKey, o.priKey); 1778 TestCase.assertEquals(secKey1, o.secKey1); 1779 } 1780 } 1781 1782 @Persistent 1783 static class SecKeyInSubclass extends SecKeyInSubclassEntity { 1784 1785 @SecondaryKey(relate=ONE_TO_ONE) 1786 String secKey2 = "2"; 1787 1788 public void validate(Object other) { 1789 super.validate(other); 1790 SecKeyInSubclass o = (SecKeyInSubclass) other; 1791 TestCase.assertEquals(secKey2, o.secKey2); 1792 } 1793 } 1794 1795 private static void checkSameIfNonNull(Object o1, Object o2) { 1796 if (o1 != null && o2 != null) { 1797 assertSame(o1, o2); 1798 } 1799 } 1800 1801 private void checkEntity(Class entityCls, MyEntity entity) 1802 throws DatabaseException { 1803 1804 Object priKey = entity.getPriKeyObject(); 1805 Class keyCls = priKey.getClass(); 1806 DatabaseEntry keyEntry2 = new DatabaseEntry(); 1807 DatabaseEntry dataEntry2 = new DatabaseEntry(); 1808 1809 /* Write object, read it back and validate (compare) it. */ 1810 PersistEntityBinding entityBinding = 1811 new PersistEntityBinding(catalog, entityCls.getName(), false); 1812 entityBinding.objectToData(entity, dataEntry); 1813 entityBinding.objectToKey(entity, keyEntry); 1814 Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); 1815 entity.validate(entity2); 1816 1817 /* Read back the primary key and validate it. */ 1818 PersistKeyBinding keyBinding = 1819 new PersistKeyBinding(catalog, keyCls.getName(), false); 1820 Object priKey2 = keyBinding.entryToObject(keyEntry); 1821 assertEquals(priKey, priKey2); 1822 keyBinding.objectToEntry(priKey2, keyEntry2); 1823 assertEquals(keyEntry, keyEntry2); 1824 1825 /* Check raw entity binding. */ 1826 PersistEntityBinding rawEntityBinding = 1827 new PersistEntityBinding(catalog, entityCls.getName(), true); 1828 RawObject rawEntity = 1829 (RawObject) rawEntityBinding.entryToObject(keyEntry, dataEntry); 1830 rawEntityBinding.objectToKey(rawEntity, keyEntry2); 1831 rawEntityBinding.objectToData(rawEntity, dataEntry2); 1832 entity2 = entityBinding.entryToObject(keyEntry2, dataEntry2); 1833 entity.validate(entity2); 1834 RawObject rawEntity2 = 1835 (RawObject) rawEntityBinding.entryToObject(keyEntry2, dataEntry2); 1836 assertEquals(rawEntity, rawEntity2); 1837 assertEquals(dataEntry, dataEntry2); 1838 assertEquals(keyEntry, keyEntry2); 1839 1840 /* Check that raw entity can be converted to a regular entity. */ 1841 entity2 = catalog.convertRawObject(rawEntity, null); 1842 entity.validate(entity2); 1843 1844 /* Check raw key binding. */ 1845 PersistKeyBinding rawKeyBinding = 1846 new PersistKeyBinding(catalog, keyCls.getName(), true); 1847 Object rawKey = rawKeyBinding.entryToObject(keyEntry); 1848 rawKeyBinding.objectToEntry(rawKey, keyEntry2); 1849 priKey2 = keyBinding.entryToObject(keyEntry2); 1850 assertEquals(priKey, priKey2); 1851 assertEquals(keyEntry, keyEntry2); 1852 } 1853 1854 private void checkSecKey(MyEntity entity, 1855 String keyName, 1856 Object keyValue, 1857 Class keyCls) 1858 throws DatabaseException { 1859 1860 checkSecKey(entity, entity.getClass(), keyName, keyValue, keyCls); 1861 } 1862 1863 private void checkSecKey(MyEntity entity, 1864 Class entityCls, 1865 String keyName, 1866 Object keyValue, 1867 Class keyCls) 1868 throws DatabaseException { 1869 1870 /* Get entity metadata. */ 1871 EntityMetadata entityMeta = 1872 model.getEntityMetadata(entityCls.getName()); 1873 assertNotNull(entityMeta); 1874 1875 /* Get secondary key metadata. */ 1876 SecondaryKeyMetadata secKeyMeta = 1877 entityMeta.getSecondaryKeys().get(keyName); 1878 assertNotNull(secKeyMeta); 1879 1880 /* Create key creator/nullifier. */ 1881 SecondaryKeyCreator keyCreator = new PersistKeyCreator 1882 (catalog, entityMeta, keyCls.getName(), secKeyMeta); 1883 1884 /* Convert entity to bytes. */ 1885 PersistEntityBinding entityBinding = 1886 new PersistEntityBinding(catalog, entityCls.getName(), false); 1887 entityBinding.objectToData(entity, dataEntry); 1888 entityBinding.objectToKey(entity, keyEntry); 1889 1890 /* Extract secondary key bytes from entity bytes. */ 1891 DatabaseEntry secKeyEntry = new DatabaseEntry(); 1892 boolean isKeyPresent = keyCreator.createSecondaryKey 1893 (null, keyEntry, dataEntry, secKeyEntry); 1894 assertEquals(keyValue != null, isKeyPresent); 1895 1896 /* Convert secondary key bytes back to an object. */ 1897 PersistKeyBinding keyBinding = 1898 new PersistKeyBinding(catalog, keyCls.getName(), false); 1899 if (isKeyPresent) { 1900 Object keyValue2 = keyBinding.entryToObject(secKeyEntry); 1901 assertEquals(keyValue, keyValue2); 1902 DatabaseEntry secKeyEntry2 = new DatabaseEntry(); 1903 keyBinding.objectToEntry(keyValue2, secKeyEntry2); 1904 assertEquals(secKeyEntry, secKeyEntry2); 1905 } 1906 } 1907 1908 private void checkSecMultiKey(MyEntity entity, 1909 String keyName, 1910 Set keyValues, 1911 Class keyCls) 1912 throws DatabaseException { 1913 1914 /* Get entity metadata. */ 1915 Class entityCls = entity.getClass(); 1916 EntityMetadata entityMeta = 1917 model.getEntityMetadata(entityCls.getName()); 1918 assertNotNull(entityMeta); 1919 1920 /* Get secondary key metadata. */ 1921 SecondaryKeyMetadata secKeyMeta = 1922 entityMeta.getSecondaryKeys().get(keyName); 1923 assertNotNull(secKeyMeta); 1924 1925 /* Create key creator/nullifier. */ 1926 SecondaryMultiKeyCreator keyCreator = new PersistKeyCreator 1927 (catalog, entityMeta, keyCls.getName(), secKeyMeta); 1928 1929 /* Convert entity to bytes. */ 1930 PersistEntityBinding entityBinding = 1931 new PersistEntityBinding(catalog, entityCls.getName(), false); 1932 entityBinding.objectToData(entity, dataEntry); 1933 entityBinding.objectToKey(entity, keyEntry); 1934 1935 /* Extract secondary key bytes from entity bytes. */ 1936 Set<DatabaseEntry> results = new HashSet<DatabaseEntry>(); 1937 keyCreator.createSecondaryKeys 1938 (null, keyEntry, dataEntry, results); 1939 assertEquals(keyValues.size(), results.size()); 1940 1941 /* Convert secondary key bytes back to objects. */ 1942 PersistKeyBinding keyBinding = 1943 new PersistKeyBinding(catalog, keyCls.getName(), false); 1944 Set keyValues2 = new HashSet(); 1945 for (DatabaseEntry secKeyEntry : results) { 1946 Object keyValue2 = keyBinding.entryToObject(secKeyEntry); 1947 keyValues2.add(keyValue2); 1948 } 1949 assertEquals(keyValues, keyValues2); 1950 } 1951 1952 private void nullifySecKey(MyEntity entity, 1953 String keyName, 1954 Object keyValue, 1955 Class keyCls) 1956 throws DatabaseException { 1957 1958 /* Get entity metadata. */ 1959 Class entityCls = entity.getClass(); 1960 EntityMetadata entityMeta = 1961 model.getEntityMetadata(entityCls.getName()); 1962 assertNotNull(entityMeta); 1963 1964 /* Get secondary key metadata. */ 1965 SecondaryKeyMetadata secKeyMeta = 1966 entityMeta.getSecondaryKeys().get(keyName); 1967 assertNotNull(secKeyMeta); 1968 1969 /* Create key creator/nullifier. */ 1970 ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator 1971 (catalog, entityMeta, keyCls.getName(), secKeyMeta); 1972 1973 /* Convert entity to bytes. */ 1974 PersistEntityBinding entityBinding = 1975 new PersistEntityBinding(catalog, entityCls.getName(), false); 1976 entityBinding.objectToData(entity, dataEntry); 1977 entityBinding.objectToKey(entity, keyEntry); 1978 1979 /* Convert secondary key to bytes. */ 1980 PersistKeyBinding keyBinding = 1981 new PersistKeyBinding(catalog, keyCls.getName(), false); 1982 DatabaseEntry secKeyEntry = new DatabaseEntry(); 1983 if (keyValue != null) { 1984 keyBinding.objectToEntry(keyValue, secKeyEntry); 1985 } 1986 1987 /* Nullify secondary key bytes within entity bytes. */ 1988 boolean isKeyPresent = keyNullifier.nullifyForeignKey 1989 (null, keyEntry, dataEntry, secKeyEntry); 1990 assertEquals(keyValue != null, isKeyPresent); 1991 1992 /* Convert modified entity bytes back to an entity. */ 1993 Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); 1994 setFieldToNull(entity, keyName); 1995 entity.validate(entity2); 1996 1997 /* Do a full check after nullifying it. */ 1998 checkSecKey(entity, keyName, null, keyCls); 1999 } 2000 2001 private void nullifySecMultiKey(MyEntity entity, 2002 String keyName, 2003 Object keyValue, 2004 Class keyCls) 2005 throws DatabaseException { 2006 2007 /* Get entity metadata. */ 2008 Class entityCls = entity.getClass(); 2009 EntityMetadata entityMeta = 2010 model.getEntityMetadata(entityCls.getName()); 2011 assertNotNull(entityMeta); 2012 2013 /* Get secondary key metadata. */ 2014 SecondaryKeyMetadata secKeyMeta = 2015 entityMeta.getSecondaryKeys().get(keyName); 2016 assertNotNull(secKeyMeta); 2017 2018 /* Create key creator/nullifier. */ 2019 ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator 2020 (catalog, entityMeta, keyCls.getName(), secKeyMeta); 2021 2022 /* Convert entity to bytes. */ 2023 PersistEntityBinding entityBinding = 2024 new PersistEntityBinding(catalog, entityCls.getName(), false); 2025 entityBinding.objectToData(entity, dataEntry); 2026 entityBinding.objectToKey(entity, keyEntry); 2027 2028 /* Get secondary key binding. */ 2029 PersistKeyBinding keyBinding = 2030 new PersistKeyBinding(catalog, keyCls.getName(), false); 2031 DatabaseEntry secKeyEntry = new DatabaseEntry(); 2032 2033 /* Nullify one key value at a time until all of them are gone. */ 2034 while (true) { 2035 Object fieldObj = getField(entity, keyName); 2036 fieldObj = nullifyFirstElement(fieldObj, keyBinding, secKeyEntry); 2037 if (fieldObj == null) { 2038 break; 2039 } 2040 setField(entity, keyName, fieldObj); 2041 2042 /* Nullify secondary key bytes within entity bytes. */ 2043 boolean isKeyPresent = keyNullifier.nullifyForeignKey 2044 (null, keyEntry, dataEntry, secKeyEntry); 2045 assertEquals(keyValue != null, isKeyPresent); 2046 2047 /* Convert modified entity bytes back to an entity. */ 2048 Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); 2049 entity.validate(entity2); 2050 2051 /* Do a full check after nullifying it. */ 2052 Set keyValues; 2053 if (fieldObj instanceof Set) { 2054 keyValues = (Set) fieldObj; 2055 } else if (fieldObj instanceof Object[]) { 2056 keyValues = toSet((Object[]) fieldObj); 2057 } else if (fieldObj instanceof int[]) { 2058 keyValues = toSet((int[]) fieldObj); 2059 } else { 2060 throw new IllegalStateException(fieldObj.getClass().getName()); 2061 } 2062 checkSecMultiKey(entity, keyName, keyValues, keyCls); 2063 } 2064 } 2065 2066 /** 2067 * Nullifies the first element of an array or collection object by removing 2068 * it from the array or collection. Returns the resulting array or 2069 * collection. Also outputs the removed element to the keyEntry using the 2070 * keyBinding. 2071 */ 2072 private Object nullifyFirstElement(Object obj, 2073 EntryBinding keyBinding, 2074 DatabaseEntry keyEntry) { 2075 if (obj instanceof Collection) { 2076 Iterator i = ((Collection) obj).iterator(); 2077 if (i.hasNext()) { 2078 Object elem = i.next(); 2079 i.remove(); 2080 keyBinding.objectToEntry(elem, keyEntry); 2081 return obj; 2082 } else { 2083 return null; 2084 } 2085 } else if (obj instanceof Object[]) { 2086 Object[] a1 = (Object[]) obj; 2087 if (a1.length > 0) { 2088 Object[] a2 = (Object[]) Array.newInstance 2089 (obj.getClass().getComponentType(), a1.length - 1); 2090 System.arraycopy(a1, 1, a2, 0, a2.length); 2091 keyBinding.objectToEntry(a1[0], keyEntry); 2092 return a2; 2093 } else { 2094 return null; 2095 } 2096 } else if (obj instanceof int[]) { 2097 int[] a1 = (int[]) obj; 2098 if (a1.length > 0) { 2099 int[] a2 = new int[a1.length - 1]; 2100 System.arraycopy(a1, 1, a2, 0, a2.length); 2101 keyBinding.objectToEntry(a1[0], keyEntry); 2102 return a2; 2103 } else { 2104 return null; 2105 } 2106 } else { 2107 throw new IllegalStateException(obj.getClass().getName()); 2108 } 2109 } 2110 2111 private void checkMetadata(String clsName, 2112 String[][] nameTypePairs, 2113 int priKeyIndex, 2114 String superClsName) 2115 throws DatabaseException { 2116 2117 /* Check metadata/types against the live model. */ 2118 checkMetadata 2119 (catalog, model, clsName, nameTypePairs, priKeyIndex, 2120 superClsName); 2121 2122 /* 2123 * Open a catalog that uses the stored model. 2124 */ 2125 PersistCatalog storedCatalog = new PersistCatalog 2126 (null, env, STORE_PREFIX, STORE_PREFIX + "catalog", null, null, 2127 null, false /*useCurrentModel*/, null /*Store*/); 2128 EntityModel storedModel = storedCatalog.getResolvedModel(); 2129 2130 /* Check metadata/types against the stored catalog/model. */ 2131 checkMetadata 2132 (storedCatalog, storedModel, clsName, nameTypePairs, priKeyIndex, 2133 superClsName); 2134 2135 storedCatalog.close(); 2136 } 2137 2138 private void checkMetadata(PersistCatalog checkCatalog, 2139 EntityModel checkModel, 2140 String clsName, 2141 String[][] nameTypePairs, 2142 int priKeyIndex, 2143 String superClsName) 2144 throws DatabaseException { 2145 2146 ClassMetadata classMeta = checkModel.getClassMetadata(clsName); 2147 assertNotNull(clsName, classMeta); 2148 2149 PrimaryKeyMetadata priKeyMeta = classMeta.getPrimaryKey(); 2150 if (priKeyIndex >= 0) { 2151 assertNotNull(priKeyMeta); 2152 String fieldName = nameTypePairs[priKeyIndex][0]; 2153 String fieldType = nameTypePairs[priKeyIndex][1]; 2154 assertEquals(priKeyMeta.getName(), fieldName); 2155 assertEquals(priKeyMeta.getClassName(), fieldType); 2156 assertEquals(priKeyMeta.getDeclaringClassName(), clsName); 2157 assertNull(priKeyMeta.getSequenceName()); 2158 } else { 2159 assertNull(priKeyMeta); 2160 } 2161 2162 RawType type = checkCatalog.getFormat(clsName); 2163 assertNotNull(type); 2164 assertEquals(clsName, type.getClassName()); 2165 assertEquals(0, type.getVersion()); 2166 assertTrue(!type.isSimple()); 2167 assertTrue(!type.isPrimitive()); 2168 assertTrue(!type.isEnum()); 2169 assertNull(type.getEnumConstants()); 2170 assertTrue(!type.isArray()); 2171 assertEquals(0, type.getDimensions()); 2172 assertNull(type.getComponentType()); 2173 RawType superType = type.getSuperType(); 2174 if (superClsName != null) { 2175 assertNotNull(superType); 2176 assertEquals(superClsName, superType.getClassName()); 2177 } else { 2178 assertNull(superType); 2179 } 2180 2181 Map<String,RawField> fields = type.getFields(); 2182 assertNotNull(fields); 2183 2184 int nFields = nameTypePairs.length; 2185 assertEquals(nFields, fields.size()); 2186 2187 for (String[] pair : nameTypePairs) { 2188 String fieldName = pair[0]; 2189 String fieldType = pair[1]; 2190 Class fieldCls; 2191 try { 2192 fieldCls = SimpleCatalog.classForName(fieldType); 2193 } catch (ClassNotFoundException e) { 2194 fail(e.toString()); 2195 return; /* For compiler */ 2196 } 2197 RawField field = fields.get(fieldName); 2198 assertNotNull(field); 2199 assertEquals(fieldName, field.getName()); 2200 type = field.getType(); 2201 assertNotNull(type); 2202 int dim = getArrayDimensions(fieldType); 2203 while (dim > 0) { 2204 assertEquals(dim, type.getDimensions()); 2205 assertEquals(dim, getArrayDimensions(fieldType)); 2206 assertEquals(true, type.isArray()); 2207 assertEquals(fieldType, type.getClassName()); 2208 assertEquals(0, type.getVersion()); 2209 assertTrue(!type.isSimple()); 2210 assertTrue(!type.isPrimitive()); 2211 assertTrue(!type.isEnum()); 2212 assertNull(type.getEnumConstants()); 2213 fieldType = getArrayComponent(fieldType, dim); 2214 type = type.getComponentType(); 2215 assertNotNull(fieldType, type); 2216 dim -= 1; 2217 } 2218 assertEquals(fieldType, type.getClassName()); 2219 List<String> enums = getEnumConstants(fieldType); 2220 assertEquals(isSimpleType(fieldType), type.isSimple()); 2221 assertEquals(isPrimitiveType(fieldType), type.isPrimitive()); 2222 assertNull(type.getComponentType()); 2223 assertTrue(!type.isArray()); 2224 assertEquals(0, type.getDimensions()); 2225 if (enums != null) { 2226 assertTrue(type.isEnum()); 2227 assertEquals(enums, type.getEnumConstants()); 2228 assertNull(type.getSuperType()); 2229 } else { 2230 assertTrue(!type.isEnum()); 2231 assertNull(type.getEnumConstants()); 2232 } 2233 } 2234 } 2235 2236 private List<String> getEnumConstants(String clsName) { 2237 if (isPrimitiveType(clsName)) { 2238 return null; 2239 } 2240 Class cls; 2241 try { 2242 cls = Class.forName(clsName); 2243 } catch (ClassNotFoundException e) { 2244 fail(e.toString()); 2245 return null; /* Never happens. */ 2246 } 2247 if (!cls.isEnum()) { 2248 return null; 2249 } 2250 List<String> enums = new ArrayList<String>(); 2251 Object[] vals = cls.getEnumConstants(); 2252 for (Object val : vals) { 2253 enums.add(val.toString()); 2254 } 2255 return enums; 2256 } 2257 2258 private String getArrayComponent(String clsName, int dim) { 2259 clsName = clsName.substring(1); 2260 if (dim > 1) { 2261 return clsName; 2262 } 2263 if (clsName.charAt(0) == 'L' && 2264 clsName.charAt(clsName.length() - 1) == ';') { 2265 return clsName.substring(1, clsName.length() - 1); 2266 } 2267 if (clsName.length() != 1) { 2268 fail(); 2269 } 2270 switch (clsName.charAt(0)) { 2271 case 'Z': return "boolean"; 2272 case 'B': return "byte"; 2273 case 'C': return "char"; 2274 case 'D': return "double"; 2275 case 'F': return "float"; 2276 case 'I': return "int"; 2277 case 'J': return "long"; 2278 case 'S': return "short"; 2279 default: fail(); 2280 } 2281 return null; /* Should never happen. */ 2282 } 2283 2284 private static int getArrayDimensions(String clsName) { 2285 int i = 0; 2286 while (clsName.charAt(i) == '[') { 2287 i += 1; 2288 } 2289 return i; 2290 } 2291 2292 private static boolean isSimpleType(String clsName) { 2293 return isPrimitiveType(clsName) || 2294 clsName.equals("java.lang.Boolean") || 2295 clsName.equals("java.lang.Character") || 2296 clsName.equals("java.lang.Byte") || 2297 clsName.equals("java.lang.Short") || 2298 clsName.equals("java.lang.Integer") || 2299 clsName.equals("java.lang.Long") || 2300 clsName.equals("java.lang.Float") || 2301 clsName.equals("java.lang.Double") || 2302 clsName.equals("java.lang.String") || 2303 clsName.equals("java.math.BigInteger") || 2304 //clsName.equals("java.math.BigDecimal") || 2305 clsName.equals("java.util.Date"); 2306 } 2307 2308 private static boolean isPrimitiveType(String clsName) { 2309 return clsName.equals("boolean") || 2310 clsName.equals("char") || 2311 clsName.equals("byte") || 2312 clsName.equals("short") || 2313 clsName.equals("int") || 2314 clsName.equals("long") || 2315 clsName.equals("float") || 2316 clsName.equals("double"); 2317 } 2318 2319 interface MyEntity { 2320 Object getPriKeyObject(); 2321 void validate(Object other); 2322 } 2323 2324 private static boolean nullOrEqual(Object o1, Object o2) { 2325 return (o1 != null) ? o1.equals(o2) : (o2 == null); 2326 } 2327 2328 private static String arrayToString(Object[] array) { 2329 StringBuffer buf = new StringBuffer(); 2330 buf.append('['); 2331 for (Object o : array) { 2332 if (o instanceof Object[]) { 2333 buf.append(arrayToString((Object[]) o)); 2334 } else { 2335 buf.append(o); 2336 } 2337 buf.append(','); 2338 } 2339 buf.append(']'); 2340 return buf.toString(); 2341 } 2342 2343 private void setFieldToNull(Object obj, String fieldName) { 2344 try { 2345 Field field = obj.getClass().getDeclaredField(fieldName); 2346 field.setAccessible(true); 2347 field.set(obj, null); 2348 } catch (NoSuchFieldException e) { 2349 fail(e.toString()); 2350 } catch (IllegalAccessException e) { 2351 fail(e.toString()); 2352 } 2353 } 2354 2355 private void setField(Object obj, String fieldName, Object fieldValue) { 2356 try { 2357 Field field = obj.getClass().getDeclaredField(fieldName); 2358 field.setAccessible(true); 2359 field.set(obj, fieldValue); 2360 } catch (NoSuchFieldException e) { 2361 throw new IllegalStateException(e.toString()); 2362 } catch (IllegalAccessException e) { 2363 throw new IllegalStateException(e.toString()); 2364 } 2365 } 2366 2367 private Object getField(Object obj, String fieldName) { 2368 try { 2369 Field field = obj.getClass().getDeclaredField(fieldName); 2370 field.setAccessible(true); 2371 return field.get(obj); 2372 } catch (NoSuchFieldException e) { 2373 throw new IllegalStateException(e.toString()); 2374 } catch (IllegalAccessException e) { 2375 throw new IllegalStateException(e.toString()); 2376 } 2377 } 2378} 2379