KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > persist > test > BindingTest


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: BindingTest.java,v 1.28 2006/11/16 04:18:20 mark Exp $
7  */

8
9 package com.sleepycat.persist.test;
10
11 import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
12 import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
13 import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
14
15 import java.io.File JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.lang.reflect.Array JavaDoc;
18 import java.lang.reflect.Field JavaDoc;
19 import java.math.BigInteger JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.Comparator JavaDoc;
24 import java.util.Date JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Locale JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Set JavaDoc;
33 import java.util.TreeMap JavaDoc;
34 import java.util.TreeSet JavaDoc;
35
36 import junit.framework.TestCase;
37
38 import com.sleepycat.bind.EntryBinding;
39 import com.sleepycat.je.DatabaseConfig;
40 import com.sleepycat.je.DatabaseEntry;
41 import com.sleepycat.je.DatabaseException;
42 import com.sleepycat.je.Environment;
43 import com.sleepycat.je.EnvironmentConfig;
44 import com.sleepycat.je.ForeignMultiKeyNullifier;
45 import com.sleepycat.je.SecondaryKeyCreator;
46 import com.sleepycat.je.SecondaryMultiKeyCreator;
47 import com.sleepycat.je.util.TestUtils;
48 import com.sleepycat.persist.impl.PersistCatalog;
49 import com.sleepycat.persist.impl.PersistComparator;
50 import com.sleepycat.persist.impl.PersistEntityBinding;
51 import com.sleepycat.persist.impl.PersistKeyBinding;
52 import com.sleepycat.persist.impl.PersistKeyCreator;
53 import com.sleepycat.persist.impl.SimpleCatalog;
54 import com.sleepycat.persist.model.AnnotationModel;
55 import com.sleepycat.persist.model.ClassMetadata;
56 import com.sleepycat.persist.model.Entity;
57 import com.sleepycat.persist.model.EntityMetadata;
58 import com.sleepycat.persist.model.EntityModel;
59 import com.sleepycat.persist.model.KeyField;
60 import com.sleepycat.persist.model.Persistent;
61 import com.sleepycat.persist.model.PersistentProxy;
62 import com.sleepycat.persist.model.PrimaryKey;
63 import com.sleepycat.persist.model.PrimaryKeyMetadata;
64 import com.sleepycat.persist.model.SecondaryKey;
65 import com.sleepycat.persist.model.SecondaryKeyMetadata;
66 import com.sleepycat.persist.raw.RawField;
67 import com.sleepycat.persist.raw.RawObject;
68 import com.sleepycat.persist.raw.RawType;
69
70 /**
71  * @author Mark Hayes
72  */

73 public class BindingTest extends TestCase {
74
75     private static final String JavaDoc STORE_PREFIX = "persist#foo#";
76
77     private File JavaDoc envHome;
78     private Environment env;
79     private EntityModel model;
80     private PersistCatalog catalog;
81     private DatabaseEntry keyEntry;
82     private DatabaseEntry dataEntry;
83
84     public void setUp()
85         throws IOException JavaDoc {
86
87         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
88         keyEntry = new DatabaseEntry();
89         dataEntry = new DatabaseEntry();
90         TestUtils.removeLogFiles("Setup", envHome, false);
91     }
92
93     public void tearDown()
94         throws IOException JavaDoc {
95
96         if (env != null) {
97             try {
98                 env.close();
99             } catch (DatabaseException e) {
100                 System.out.println("During tearDown: " + e);
101             }
102         }
103         try {
104             TestUtils.removeLogFiles("TearDown", envHome, false);
105         } catch (Error JavaDoc e) {
106             System.out.println("During tearDown: " + e);
107         }
108         envHome = null;
109         env = null;
110         catalog = null;
111         keyEntry = null;
112         dataEntry = null;
113     }
114
115     private void open()
116         throws DatabaseException {
117
118         EnvironmentConfig envConfig = new EnvironmentConfig();
119         envConfig.setAllowCreate(true);
120         env = new Environment(envHome, envConfig);
121
122         openCatalog();
123     }
124
125     private void openCatalog()
126         throws DatabaseException {
127
128         model = new AnnotationModel();
129         model.registerClass(LocalizedTextProxy.class);
130         model.registerClass(LocaleProxy.class);
131
132         DatabaseConfig dbConfig = new DatabaseConfig();
133         dbConfig.setAllowCreate(true);
134         catalog = new PersistCatalog
135             (null, env, STORE_PREFIX, "catalog", dbConfig, model, null,
136              false /*rawAccess*/, null /*Store*/);
137     }
138
139     private void close()
140         throws DatabaseException {
141
142         /* Close/open/close catalog to test checks for class evolution. */
143         catalog.close();
144         PersistCatalog.expectNoClassChanges = true;
145         try {
146             openCatalog();
147         } finally {
148             PersistCatalog.expectNoClassChanges = false;
149         }
150         catalog.close();
151         catalog = null;
152
153         env.close();
154         env = null;
155     }
156
157     public void testBasic()
158         throws DatabaseException {
159
160         open();
161
162         checkEntity(Basic.class,
163                     new Basic(1, "one", 2.2, "three"));
164         checkEntity(Basic.class,
165                     new Basic(0, null, 0, null));
166         checkEntity(Basic.class,
167                     new Basic(-1, "xxx", -2, "xxx"));
168
169         checkMetadata(Basic.class.getName(), new String JavaDoc[][] {
170                           {"id", "long"},
171                           {"one", "java.lang.String"},
172                           {"two", "double"},
173                           {"three", "java.lang.String"},
174                       },
175                       0 /*priKeyIndex*/, null);
176
177         close();
178     }
179
180     @Entity
181     static class Basic implements MyEntity {
182
183         @PrimaryKey
184         private long id;
185         private String JavaDoc one;
186         private double two;
187         private String JavaDoc three;
188
189         private Basic() { }
190
191         private Basic(long id, String JavaDoc one, double two, String JavaDoc three) {
192             this.id = id;
193             this.one = one;
194             this.two = two;
195             this.three = three;
196         }
197
198         public String JavaDoc getBasicOne() {
199             return one;
200         }
201
202         public Object JavaDoc getPriKeyObject() {
203             return id;
204         }
205
206         public void validate(Object JavaDoc other) {
207             Basic o = (Basic) other;
208             TestCase.assertEquals(id, o.id);
209             TestCase.assertTrue(nullOrEqual(one, o.one));
210             TestCase.assertEquals(two, o.two);
211             TestCase.assertTrue(nullOrEqual(three, o.three));
212             if (one == three) {
213                 TestCase.assertSame(o.one, o.three);
214             }
215         }
216
217         @Override JavaDoc
218         public String JavaDoc toString() {
219             return "" + id + ' ' + one + ' ' + two;
220         }
221     }
222
223     public void testSimpleTypes()
224         throws DatabaseException {
225
226         open();
227
228         checkEntity(SimpleTypes.class, new SimpleTypes());
229
230         checkMetadata(SimpleTypes.class.getName(), new String JavaDoc[][] {
231                           {"f0", "boolean"},
232                           {"f1", "char"},
233                           {"f2", "byte"},
234                           {"f3", "short"},
235                           {"f4", "int"},
236                           {"f5", "long"},
237                           {"f6", "float"},
238                           {"f7", "double"},
239                           {"f8", "java.lang.String"},
240                           {"f9", "java.math.BigInteger"},
241                           //{"f10", "java.math.BigDecimal"},
242
{"f11", "java.util.Date"},
243                           {"f12", "java.lang.Boolean"},
244                           {"f13", "java.lang.Character"},
245                           {"f14", "java.lang.Byte"},
246                           {"f15", "java.lang.Short"},
247                           {"f16", "java.lang.Integer"},
248                           {"f17", "java.lang.Long"},
249                           {"f18", "java.lang.Float"},
250                           {"f19", "java.lang.Double"},
251                       },
252                       0 /*priKeyIndex*/, null);
253
254         close();
255     }
256
257     @Entity
258     static class SimpleTypes implements MyEntity {
259
260         @PrimaryKey
261         private boolean f0 = true;
262         private char f1 = 'a';
263         private byte f2 = 123;
264         private short f3 = 123;
265         private int f4 = 123;
266         private long f5 = 123;
267         private float f6 = 123.4f;
268         private double f7 = 123.4;
269         private String JavaDoc f8 = "xxx";
270         private BigInteger JavaDoc f9 = BigInteger.valueOf(123);
271         //private BigDecimal f10 = BigDecimal.valueOf(123.4);
272
private Date JavaDoc f11 = new Date JavaDoc();
273         private Boolean JavaDoc f12 = true;
274         private Character JavaDoc f13 = 'a';
275         private Byte JavaDoc f14 = 123;
276         private Short JavaDoc f15 = 123;
277         private Integer JavaDoc f16 = 123;
278         private Long JavaDoc f17 = 123L;
279         private Float JavaDoc f18 = 123.4f;
280         private Double JavaDoc f19 = 123.4;
281
282         SimpleTypes() { }
283
284         public Object JavaDoc getPriKeyObject() {
285             return f0;
286         }
287
288         public void validate(Object JavaDoc other) {
289             SimpleTypes o = (SimpleTypes) other;
290             TestCase.assertEquals(f0, o.f0);
291             TestCase.assertEquals(f1, o.f1);
292             TestCase.assertEquals(f2, o.f2);
293             TestCase.assertEquals(f3, o.f3);
294             TestCase.assertEquals(f4, o.f4);
295             TestCase.assertEquals(f5, o.f5);
296             TestCase.assertEquals(f6, o.f6);
297             TestCase.assertEquals(f7, o.f7);
298             TestCase.assertEquals(f8, o.f8);
299             TestCase.assertEquals(f9, o.f9);
300             //TestCase.assertEquals(f10, o.f10);
301
TestCase.assertEquals(f11, o.f11);
302             TestCase.assertEquals(f12, o.f12);
303             TestCase.assertEquals(f13, o.f13);
304             TestCase.assertEquals(f14, o.f14);
305             TestCase.assertEquals(f15, o.f15);
306             TestCase.assertEquals(f16, o.f16);
307             TestCase.assertEquals(f17, o.f17);
308             TestCase.assertEquals(f18, o.f18);
309             TestCase.assertEquals(f19, o.f19);
310         }
311     }
312
313     public void testArrayTypes()
314         throws DatabaseException {
315
316         open();
317
318         checkEntity(ArrayTypes.class, new ArrayTypes());
319
320         checkMetadata(ArrayTypes.class.getName(), new String JavaDoc[][] {
321                           {"id", "int"},
322                           {"f0", boolean[].class.getName()},
323                           {"f1", char[].class.getName()},
324                           {"f2", byte[].class.getName()},
325                           {"f3", short[].class.getName()},
326                           {"f4", int[].class.getName()},
327                           {"f5", long[].class.getName()},
328                           {"f6", float[].class.getName()},
329                           {"f7", double[].class.getName()},
330                           {"f8", String JavaDoc[].class.getName()},
331                           {"f9", Address[].class.getName()},
332                           {"f10", boolean[][][].class.getName()},
333                           {"f11", String JavaDoc[][][].class.getName()},
334                       },
335                       0 /*priKeyIndex*/, null);
336
337         close();
338     }
339
340     @Entity
341     static class ArrayTypes implements MyEntity {
342
343         @PrimaryKey
344         private int id = 1;
345         private boolean[] f0 = {false, true};
346         private char[] f1 = {'a', 'b'};
347         private byte[] f2 = {1, 2};
348         private short[] f3 = {1, 2};
349         private int[] f4 = {1, 2};
350         private long[] f5 = {1, 2};
351         private float[] f6 = {1.1f, 2.2f};
352         private double[] f7 = {1.1, 2,2};
353         private String JavaDoc[] f8 = {"xxx", null, "yyy"};
354         private Address[] f9 = {new Address("city", "state", 123),
355                                 null,
356                                 new Address("x", "y", 444)};
357         private boolean[][][] f10 =
358         {
359             {
360                 {false, true},
361                 {false, true},
362             },
363             null,
364             {
365                 {false, true},
366                 {false, true},
367             },
368         };
369         private String JavaDoc[][][] f11 =
370         {
371             {
372                 {"xxx", null, "yyy"},
373                 null,
374                 {"xxx", null, "yyy"},
375             },
376             null,
377             {
378                 {"xxx", null, "yyy"},
379                 null,
380                 {"xxx", null, "yyy"},
381             },
382         };
383
384         ArrayTypes() { }
385
386         public Object JavaDoc getPriKeyObject() {
387             return id;
388         }
389
390         public void validate(Object JavaDoc other) {
391             ArrayTypes o = (ArrayTypes) other;
392             TestCase.assertEquals(id, o.id);
393             TestCase.assertTrue(Arrays.equals(f0, o.f0));
394             TestCase.assertTrue(Arrays.equals(f1, o.f1));
395             TestCase.assertTrue(Arrays.equals(f2, o.f2));
396             TestCase.assertTrue(Arrays.equals(f3, o.f3));
397             TestCase.assertTrue(Arrays.equals(f4, o.f4));
398             TestCase.assertTrue(Arrays.equals(f5, o.f5));
399             TestCase.assertTrue(Arrays.equals(f6, o.f6));
400             TestCase.assertTrue(Arrays.equals(f7, o.f7));
401             TestCase.assertTrue(Arrays.equals(f8, o.f8));
402             TestCase.assertTrue(Arrays.deepEquals(f9, o.f9));
403             TestCase.assertTrue(Arrays.deepEquals(f10, o.f10));
404             TestCase.assertTrue(Arrays.deepEquals(f11, o.f11));
405         }
406     }
407
408     public void testEnumTypes()
409         throws DatabaseException {
410
411         open();
412
413         checkEntity(EnumTypes.class, new EnumTypes());
414
415         checkMetadata(EnumTypes.class.getName(), new String JavaDoc[][] {
416                           {"f0", "int"},
417                           {"f1", Thread.State JavaDoc.class.getName()},
418                           {"f2", EnumTypes.MyEnum.class.getName()},
419                           {"f3", Object JavaDoc.class.getName()},
420                       },
421                       0 /*priKeyIndex*/, null);
422
423         close();
424     }
425
426     @Entity
427     static class EnumTypes implements MyEntity {
428
429         private static enum MyEnum { ONE, TWO };
430
431         @PrimaryKey
432         private int f0 = 1;
433         private Thread.State JavaDoc f1 = Thread.State.RUNNABLE;
434         private MyEnum f2 = MyEnum.ONE;
435         private Object JavaDoc f3 = MyEnum.TWO;
436
437         EnumTypes() { }
438
439         public Object JavaDoc getPriKeyObject() {
440             return f0;
441         }
442
443         public void validate(Object JavaDoc other) {
444             EnumTypes o = (EnumTypes) other;
445             TestCase.assertEquals(f0, o.f0);
446             TestCase.assertSame(f1, o.f1);
447             TestCase.assertSame(f2, o.f2);
448             TestCase.assertSame(f3, o.f3);
449         }
450     }
451
452     public void testProxyTypes()
453         throws DatabaseException {
454
455         open();
456
457         checkEntity(ProxyTypes.class, new ProxyTypes());
458
459         checkMetadata(ProxyTypes.class.getName(), new String JavaDoc[][] {
460                           {"f0", "int"},
461                           {"f1", Locale JavaDoc.class.getName()},
462                           {"f2", Set JavaDoc.class.getName()},
463                           {"f3", Set JavaDoc.class.getName()},
464                           {"f4", Object JavaDoc.class.getName()},
465                           {"f5", HashMap JavaDoc.class.getName()},
466                           {"f6", TreeMap JavaDoc.class.getName()},
467                           {"f7", List JavaDoc.class.getName()},
468                           {"f8", LinkedList JavaDoc.class.getName()},
469                           {"f9", LocalizedText.class.getName()},
470                       },
471                       0 /*priKeyIndex*/, null);
472
473         close();
474     }
475
476     @Entity
477     static class ProxyTypes implements MyEntity {
478
479         @PrimaryKey
480         private int f0 = 1;
481         private Locale JavaDoc f1 = Locale.getDefault();
482         private Set JavaDoc<Integer JavaDoc> f2 = new HashSet JavaDoc<Integer JavaDoc>();
483         private Set JavaDoc<Integer JavaDoc> f3 = new TreeSet JavaDoc<Integer JavaDoc>();
484         private Object JavaDoc f4 = new HashSet JavaDoc<Address>();
485         private HashMap JavaDoc<String JavaDoc,Integer JavaDoc> f5 = new HashMap JavaDoc<String JavaDoc,Integer JavaDoc>();
486         private TreeMap JavaDoc<String JavaDoc,Address> f6 = new TreeMap JavaDoc<String JavaDoc,Address>();
487         private List JavaDoc<Integer JavaDoc> f7 = new ArrayList JavaDoc<Integer JavaDoc>();
488         private LinkedList JavaDoc<Integer JavaDoc> f8 = new LinkedList JavaDoc<Integer JavaDoc>();
489         private LocalizedText f9 = new LocalizedText(f1, "xyz");
490
491         ProxyTypes() {
492             f2.add(123);
493             f2.add(456);
494             f3.add(456);
495             f3.add(123);
496             HashSet JavaDoc<Address> s = (HashSet JavaDoc) f4;
497             s.add(new Address("city", "state", 11111));
498             s.add(new Address("city2", "state2", 22222));
499             s.add(new Address("city3", "state3", 33333));
500             f5.put("one", 111);
501             f5.put("two", 222);
502             f5.put("three", 333);
503             f6.put("one", new Address("city", "state", 11111));
504             f6.put("two", new Address("city2", "state2", 22222));
505             f6.put("three", new Address("city3", "state3", 33333));
506             f7.add(123);
507             f7.add(456);
508             f8.add(123);
509             f8.add(456);
510         }
511
512         public Object JavaDoc getPriKeyObject() {
513             return f0;
514         }
515
516         public void validate(Object JavaDoc other) {
517             ProxyTypes o = (ProxyTypes) other;
518             TestCase.assertEquals(f0, o.f0);
519             TestCase.assertEquals(f1, o.f1);
520             TestCase.assertEquals(f2, o.f2);
521             TestCase.assertEquals(f3, o.f3);
522             TestCase.assertEquals(f4, o.f4);
523             TestCase.assertEquals(f5, o.f5);
524             TestCase.assertEquals(f6, o.f6);
525             TestCase.assertEquals(f7, o.f7);
526             TestCase.assertEquals(f8, o.f8);
527             TestCase.assertEquals(f9, o.f9);
528         }
529     }
530
531     @Persistent(proxyFor=Locale JavaDoc.class)
532     static class LocaleProxy implements PersistentProxy<Locale JavaDoc> {
533
534         String JavaDoc language;
535         String JavaDoc country;
536         String JavaDoc variant;
537
538         private LocaleProxy() {}
539
540         public void initializeProxy(Locale JavaDoc object) {
541             language = object.getLanguage();
542             country = object.getCountry();
543             variant = object.getVariant();
544         }
545
546         public Locale JavaDoc convertProxy() {
547             return new Locale JavaDoc(language, country, variant);
548         }
549     }
550
551     static class LocalizedText {
552
553         Locale JavaDoc locale;
554         String JavaDoc text;
555
556         LocalizedText(Locale JavaDoc locale, String JavaDoc text) {
557             this.locale = locale;
558             this.text = text;
559         }
560
561         @Override JavaDoc
562         public boolean equals(Object JavaDoc other) {
563             LocalizedText o = (LocalizedText) other;
564             return text.equals(o.text) &&
565                    locale.equals(o.locale);
566         }
567     }
568
569     @Persistent(proxyFor=LocalizedText.class)
570     static class LocalizedTextProxy implements PersistentProxy<LocalizedText> {
571
572         Locale JavaDoc locale;
573         String JavaDoc text;
574
575         private LocalizedTextProxy() {}
576
577         public void initializeProxy(LocalizedText object) {
578             locale = object.locale;
579             text = object.text;
580         }
581
582         public LocalizedText convertProxy() {
583             return new LocalizedText(locale, text);
584         }
585     }
586
587     public void testEmbedded()
588         throws DatabaseException {
589
590         open();
591
592         Address a1 = new Address("city", "state", 123);
593         Address a2 = new Address("Wikieup", "AZ", 85360);
594
595         checkEntity(Embedded.class,
596                     new Embedded("x", a1, a2));
597         checkEntity(Embedded.class,
598                     new Embedded("y", a1, null));
599         checkEntity(Embedded.class,
600                     new Embedded("", a2, a2));
601
602         checkMetadata(Embedded.class.getName(), new String JavaDoc[][] {
603                         {"id", "java.lang.String"},
604                         {"idShadow", "java.lang.String"},
605                         {"one", Address.class.getName()},
606                         {"two", Address.class.getName()},
607                       },
608                       0 /*priKeyIndex*/, null);
609
610         checkMetadata(Address.class.getName(), new String JavaDoc[][] {
611                         {"street", "java.lang.String"},
612                         {"city", "java.lang.String"},
613                         {"zip", "int"},
614                       },
615                       -1 /*priKeyIndex*/, null);
616
617         close();
618     }
619
620     @Entity
621     static class Embedded implements MyEntity {
622
623         @PrimaryKey
624         private String JavaDoc id;
625         private String JavaDoc idShadow;
626         private Address one;
627         private Address two;
628
629         private Embedded() { }
630
631         private Embedded(String JavaDoc id, Address one, Address two) {
632             this.id = id;
633             idShadow = id;
634             this.one = one;
635             this.two = two;
636         }
637
638         public Object JavaDoc getPriKeyObject() {
639             return id;
640         }
641
642         public void validate(Object JavaDoc other) {
643             Embedded o = (Embedded) other;
644             TestCase.assertEquals(id, o.id);
645             if (one != null) {
646                 one.validate(o.one);
647             } else {
648                 assertNull(o.one);
649             }
650             if (two != null) {
651                 two.validate(o.two);
652             } else {
653                 assertNull(o.two);
654             }
655             TestCase.assertSame(o.id, o.idShadow);
656             if (one == two) {
657                 TestCase.assertSame(o.one, o.two);
658             }
659         }
660
661         @Override JavaDoc
662         public String JavaDoc toString() {
663             return "" + id + ' ' + one + ' ' + two;
664         }
665     }
666
667     @Persistent
668     static class Address {
669
670         private String JavaDoc street;
671         private String JavaDoc city;
672         private int zip;
673
674         private Address() {}
675
676         Address(String JavaDoc street, String JavaDoc city, int zip) {
677             this.street = street;
678             this.city = city;
679             this.zip = zip;
680         }
681
682         void validate(Address o) {
683             TestCase.assertTrue(nullOrEqual(street, o.street));
684             TestCase.assertTrue(nullOrEqual(city, o.city));
685             TestCase.assertEquals(zip, o.zip);
686         }
687
688         @Override JavaDoc
689         public String JavaDoc toString() {
690             return "" + street + ' ' + city + ' ' + zip;
691         }
692
693         @Override JavaDoc
694         public boolean equals(Object JavaDoc other) {
695             if (other == null) {
696                 return false;
697             }
698             Address o = (Address) other;
699             return nullOrEqual(street, o.street) &&
700                    nullOrEqual(city, o.city) &&
701                    nullOrEqual(zip, o.zip);
702         }
703
704         @Override JavaDoc
705         public int hashCode() {
706             return zip;
707         }
708     }
709
710     public void testSubclass()
711         throws DatabaseException {
712
713         open();
714
715         checkEntity(Basic.class,
716                     new Subclass(-1, "xxx", -2, "xxx", "xxx", true));
717
718         checkMetadata(Basic.class.getName(), new String JavaDoc[][] {
719                           {"id", "long"},
720                           {"one", "java.lang.String"},
721                           {"two", "double"},
722                           {"three", "java.lang.String"},
723                       },
724                       0 /*priKeyIndex*/, null);
725         checkMetadata(Subclass.class.getName(), new String JavaDoc[][] {
726                           {"one", "java.lang.String"},
727                           {"two", "boolean"},
728                       },
729                       -1 /*priKeyIndex*/, Basic.class.getName());
730
731         close();
732     }
733
734     @Persistent
735     static class Subclass extends Basic {
736
737         private String JavaDoc one;
738         private boolean two;
739
740     private Subclass() {
741     }
742
743         private Subclass(long id, String JavaDoc one, double two, String JavaDoc three,
744                          String JavaDoc subOne, boolean subTwo) {
745             super(id, one, two, three);
746             this.one = subOne;
747             this.two = subTwo;
748     }
749
750         public void validate(Object JavaDoc other) {
751             super.validate(other);
752             Subclass o = (Subclass) other;
753             TestCase.assertTrue(nullOrEqual(one, o.one));
754             TestCase.assertEquals(two, o.two);
755             if (one == getBasicOne()) {
756                 TestCase.assertSame(o.one, o.getBasicOne());
757             }
758         }
759     }
760
761     public void testSuperclass()
762         throws DatabaseException {
763
764         open();
765
766         checkEntity(UseSuperclass.class,
767                     new UseSuperclass(33, "xxx"));
768
769         checkMetadata(Superclass.class.getName(), new String JavaDoc[][] {
770                           {"id", "int"},
771                           {"one", "java.lang.String"},
772                       },
773                       0 /*priKeyIndex*/, null);
774         checkMetadata(UseSuperclass.class.getName(), new String JavaDoc[][] {
775                       },
776                       -1 /*priKeyIndex*/, Superclass.class.getName());
777
778         close();
779     }
780
781     @Persistent
782     static class Superclass implements MyEntity {
783
784         @PrimaryKey
785         private int id;
786         private String JavaDoc one;
787
788         private Superclass() { }
789
790         private Superclass(int id, String JavaDoc one) {
791             this.id = id;
792             this.one = one;
793         }
794
795         public Object JavaDoc getPriKeyObject() {
796             return id;
797         }
798
799         public void validate(Object JavaDoc other) {
800             Superclass o = (Superclass) other;
801             TestCase.assertEquals(id, o.id);
802             TestCase.assertTrue(nullOrEqual(one, o.one));
803         }
804     }
805
806     @Entity
807     static class UseSuperclass extends Superclass {
808
809         private UseSuperclass() { }
810
811         private UseSuperclass(int id, String JavaDoc one) {
812             super(id, one);
813         }
814     }
815
816     public void testAbstract()
817         throws DatabaseException {
818
819         open();
820
821         checkEntity(EntityUseAbstract.class,
822                     new EntityUseAbstract(33, "xxx"));
823
824         checkMetadata(Abstract.class.getName(), new String JavaDoc[][] {
825                           {"one", "java.lang.String"},
826                       },
827                       -1 /*priKeyIndex*/, null);
828         checkMetadata(EmbeddedUseAbstract.class.getName(), new String JavaDoc[][] {
829                           {"two", "java.lang.String"},
830                       },
831                       -1 /*priKeyIndex*/, Abstract.class.getName());
832         checkMetadata(EntityUseAbstract.class.getName(), new String JavaDoc[][] {
833                           {"id", "int"},
834                           {"f1", EmbeddedUseAbstract.class.getName()},
835                           {"f2", Abstract.class.getName()},
836                           {"f3", Object JavaDoc.class.getName()},
837                           {"f4", Interface.class.getName()},
838                           {"a1", EmbeddedUseAbstract[].class.getName()},
839                           {"a2", Abstract[].class.getName()},
840                           {"a3", Abstract[].class.getName()},
841                           {"a4", Object JavaDoc[].class.getName()},
842                           {"a5", Interface[].class.getName()},
843                           {"a6", Interface[].class.getName()},
844                           {"a7", Interface[].class.getName()},
845                       },
846                       0 /*priKeyIndex*/, Abstract.class.getName());
847
848         close();
849     }
850
851     @Persistent
852     static abstract class Abstract implements Interface {
853
854         String JavaDoc one;
855
856         private Abstract() { }
857
858         private Abstract(String JavaDoc one) {
859             this.one = one;
860         }
861
862         public void validate(Object JavaDoc other) {
863             Abstract o = (Abstract) other;
864             TestCase.assertTrue(nullOrEqual(one, o.one));
865         }
866
867         @Override JavaDoc
868         public boolean equals(Object JavaDoc other) {
869             Abstract o = (Abstract) other;
870             return nullOrEqual(one, o.one);
871         }
872     }
873
874     interface Interface {
875         void validate(Object JavaDoc other);
876     }
877
878     @Persistent
879     static class EmbeddedUseAbstract extends Abstract {
880
881         private String JavaDoc two;
882
883         private EmbeddedUseAbstract() { }
884
885         private EmbeddedUseAbstract(String JavaDoc one, String JavaDoc two) {
886             super(one);
887             this.two = two;
888         }
889
890         @Override JavaDoc
891         public void validate(Object JavaDoc other) {
892             super.validate(other);
893             EmbeddedUseAbstract o = (EmbeddedUseAbstract) other;
894             TestCase.assertTrue(nullOrEqual(two, o.two));
895         }
896
897         @Override JavaDoc
898         public boolean equals(Object JavaDoc other) {
899             if (!super.equals(other)) {
900                 return false;
901             }
902             EmbeddedUseAbstract o = (EmbeddedUseAbstract) other;
903             return nullOrEqual(two, o.two);
904         }
905     }
906
907     @Entity
908     static class EntityUseAbstract extends Abstract implements MyEntity {
909
910         @PrimaryKey
911         private int id;
912
913         private EmbeddedUseAbstract f1;
914         private Abstract f2;
915         private Object JavaDoc f3;
916         private Interface f4;
917         private EmbeddedUseAbstract[] a1;
918         private Abstract[] a2;
919         private Abstract[] a3;
920         private Object JavaDoc[] a4;
921         private Interface[] a5;
922         private Interface[] a6;
923         private Interface[] a7;
924
925         private EntityUseAbstract() { }
926
927         private EntityUseAbstract(int id, String JavaDoc one) {
928             super(one);
929             this.id = id;
930             f1 = new EmbeddedUseAbstract(one, one);
931             f2 = new EmbeddedUseAbstract(one + "x", one + "y");
932             f3 = new EmbeddedUseAbstract(null, null);
933             f4 = new EmbeddedUseAbstract(null, null);
934             a1 = new EmbeddedUseAbstract[3];
935             a2 = new EmbeddedUseAbstract[3];
936             a3 = new Abstract[3];
937             a4 = new Object JavaDoc[3];
938             a5 = new EmbeddedUseAbstract[3];
939             a6 = new Abstract[3];
940             a7 = new Interface[3];
941             for (int i = 0; i < 3; i += 1) {
942                 a1[i] = new EmbeddedUseAbstract("1" + i, null);
943                 a2[i] = new EmbeddedUseAbstract("2" + i, null);
944                 a3[i] = new EmbeddedUseAbstract("3" + i, null);
945                 a4[i] = new EmbeddedUseAbstract("4" + i, null);
946                 a5[i] = new EmbeddedUseAbstract("5" + i, null);
947                 a6[i] = new EmbeddedUseAbstract("6" + i, null);
948                 a7[i] = new EmbeddedUseAbstract("7" + i, null);
949             }
950         }
951
952         public Object JavaDoc getPriKeyObject() {
953             return id;
954         }
955
956         @Override JavaDoc
957         public void validate(Object JavaDoc other) {
958             super.validate(other);
959             EntityUseAbstract o = (EntityUseAbstract) other;
960             TestCase.assertEquals(id, o.id);
961             f1.validate(o.f1);
962             assertSame(o.one, o.f1.one);
963             assertSame(o.f1.one, o.f1.two);
964             f2.validate(o.f2);
965             ((Abstract) f3).validate(o.f3);
966             f4.validate(o.f4);
967             assertTrue(arrayToString(a1) + ' ' + arrayToString(o.a1),
968                        Arrays.equals(a1, o.a1));
969             assertTrue(Arrays.equals(a2, o.a2));
970             assertTrue(Arrays.equals(a3, o.a3));
971             assertTrue(Arrays.equals(a4, o.a4));
972             assertTrue(Arrays.equals(a5, o.a5));
973             assertTrue(Arrays.equals(a6, o.a6));
974             assertTrue(Arrays.equals(a7, o.a7));
975             assertSame(EmbeddedUseAbstract.class, f2.getClass());
976             assertSame(EmbeddedUseAbstract.class, f3.getClass());
977             assertSame(EmbeddedUseAbstract[].class, a1.getClass());
978             assertSame(EmbeddedUseAbstract[].class, a2.getClass());
979             assertSame(Abstract[].class, a3.getClass());
980             assertSame(Object JavaDoc[].class, a4.getClass());
981             assertSame(EmbeddedUseAbstract[].class, a5.getClass());
982             assertSame(Abstract[].class, a6.getClass());
983             assertSame(Interface[].class, a7.getClass());
984         }
985     }
986
987     public void testCompositeKey()
988         throws DatabaseException {
989
990         open();
991
992         CompositeKey key =
993             new CompositeKey(123, 456L, "xyz", BigInteger.valueOf(789));
994         checkEntity(UseCompositeKey.class,
995                     new UseCompositeKey(key, "one"));
996
997         checkMetadata(UseCompositeKey.class.getName(), new String JavaDoc[][] {
998                           {"key", CompositeKey.class.getName()},
999                           {"one", "java.lang.String"},
1000                      },
1001                      0 /*priKeyIndex*/, null);
1002
1003        checkMetadata(CompositeKey.class.getName(), new String JavaDoc[][] {
1004                        {"f1", "int"},
1005                        {"f2", "java.lang.Long"},
1006                        {"f3", "java.lang.String"},
1007                        {"f4", "java.math.BigInteger"},
1008                      },
1009                      -1 /*priKeyIndex*/, null);
1010
1011        close();
1012    }
1013
1014    @Persistent
1015    static class CompositeKey {
1016        @KeyField(3)
1017        private int f1;
1018        @KeyField(2)
1019        private Long JavaDoc f2;
1020        @KeyField(1)
1021        private String JavaDoc f3;
1022        @KeyField(4)
1023        private BigInteger JavaDoc f4;
1024
1025        private CompositeKey() {}
1026
1027        CompositeKey(int f1, Long JavaDoc f2, String JavaDoc f3, BigInteger JavaDoc f4) {
1028            this.f1 = f1;
1029            this.f2 = f2;
1030            this.f3 = f3;
1031            this.f4 = f4;
1032        }
1033
1034        void validate(CompositeKey o) {
1035            TestCase.assertEquals(f1, o.f1);
1036            TestCase.assertTrue(nullOrEqual(f2, o.f2));
1037            TestCase.assertTrue(nullOrEqual(f3, o.f3));
1038            TestCase.assertTrue(nullOrEqual(f4, o.f4));
1039        }
1040
1041        @Override JavaDoc
1042        public boolean equals(Object JavaDoc other) {
1043            CompositeKey o = (CompositeKey) other;
1044            return f1 == o.f1 &&
1045                   nullOrEqual(f2, o.f2) &&
1046                   nullOrEqual(f3, o.f3) &&
1047                   nullOrEqual(f4, o.f4);
1048        }
1049
1050        @Override JavaDoc
1051        public int hashCode() {
1052            return f1;
1053        }
1054
1055        @Override JavaDoc
1056        public String JavaDoc toString() {
1057            return "" + f1 + ' ' + f2 + ' ' + f3 + ' ' + f4;
1058        }
1059    }
1060
1061    @Entity
1062    static class UseCompositeKey implements MyEntity {
1063
1064        @PrimaryKey
1065        private CompositeKey key;
1066        private String JavaDoc one;
1067
1068        private UseCompositeKey() { }
1069
1070        private UseCompositeKey(CompositeKey key, String JavaDoc one) {
1071            this.key = key;
1072            this.one = one;
1073        }
1074
1075        public Object JavaDoc getPriKeyObject() {
1076            return key;
1077        }
1078
1079        public void validate(Object JavaDoc other) {
1080            UseCompositeKey o = (UseCompositeKey) other;
1081            TestCase.assertNotNull(key);
1082            TestCase.assertNotNull(o.key);
1083            key.validate(o.key);
1084            TestCase.assertTrue(nullOrEqual(one, o.one));
1085        }
1086    }
1087
1088    public void testComparableKey()
1089        throws DatabaseException {
1090
1091        open();
1092
1093        ComparableKey key = new ComparableKey(123, 456);
1094        checkEntity(UseComparableKey.class,
1095                    new UseComparableKey(key, "one"));
1096
1097        checkMetadata(UseComparableKey.class.getName(), new String JavaDoc[][] {
1098                          {"key", ComparableKey.class.getName()},
1099                          {"one", "java.lang.String"},
1100                      },
1101                      0 /*priKeyIndex*/, null);
1102
1103        checkMetadata(ComparableKey.class.getName(), new String JavaDoc[][] {
1104                        {"f1", "int"},
1105                        {"f2", "int"},
1106                      },
1107                      -1 /*priKeyIndex*/, null);
1108
1109        ClassMetadata classMeta =
1110            model.getClassMetadata(UseComparableKey.class.getName());
1111        assertNotNull(classMeta);
1112
1113        PersistKeyBinding binding = new PersistKeyBinding
1114            (catalog, ComparableKey.class.getName(), false);
1115
1116        PersistComparator comparator = new PersistComparator
1117            (ComparableKey.class.getName(),
1118             classMeta.getCompositeKeyFields(),
1119             binding);
1120
1121        compareKeys(comparator, binding, new ComparableKey(1, 1),
1122                                         new ComparableKey(1, 1), 0);
1123        compareKeys(comparator, binding, new ComparableKey(1, 2),
1124                                         new ComparableKey(1, 1), -1);
1125        compareKeys(comparator, binding, new ComparableKey(2, 1),
1126                                         new ComparableKey(1, 1), -1);
1127        compareKeys(comparator, binding, new ComparableKey(2, 1),
1128                                         new ComparableKey(3, 1), 1);
1129
1130        close();
1131    }
1132
1133    private void compareKeys(Comparator JavaDoc<Object JavaDoc> comparator,
1134                             EntryBinding binding,
1135                             Object JavaDoc key1,
1136                             Object JavaDoc key2,
1137                             int expectResult) {
1138        DatabaseEntry entry1 = new DatabaseEntry();
1139        DatabaseEntry entry2 = new DatabaseEntry();
1140        binding.objectToEntry(key1, entry1);
1141        binding.objectToEntry(key2, entry2);
1142        int result = comparator.compare(entry1.getData(), entry2.getData());
1143        assertEquals(expectResult, result);
1144    }
1145
1146    @Persistent
1147    static class ComparableKey implements Comparable JavaDoc<ComparableKey> {
1148        @KeyField(2)
1149        private int f1;
1150        @KeyField(1)
1151        private int f2;
1152
1153        private ComparableKey() {}
1154
1155        ComparableKey(int f1, int f2) {
1156            this.f1 = f1;
1157            this.f2 = f2;
1158        }
1159
1160        void validate(ComparableKey o) {
1161            TestCase.assertEquals(f1, o.f1);
1162            TestCase.assertEquals(f2, o.f2);
1163        }
1164
1165        @Override JavaDoc
1166        public boolean equals(Object JavaDoc other) {
1167            ComparableKey o = (ComparableKey) other;
1168            return f1 == o.f1 && f2 == o.f2;
1169        }
1170
1171        @Override JavaDoc
1172        public int hashCode() {
1173            return f1 + f2;
1174        }
1175
1176        @Override JavaDoc
1177        public String JavaDoc toString() {
1178            return "" + f1 + ' ' + f2;
1179        }
1180
1181        /** Compare f1 then f2, in reverse integer order. */
1182        public int compareTo(ComparableKey o) {
1183            if (f1 != o.f1) {
1184                return o.f1 - f1;
1185            } else {
1186                return o.f2 - f2;
1187            }
1188        }
1189    }
1190
1191    @Entity
1192    static class UseComparableKey implements MyEntity {
1193
1194        @PrimaryKey
1195        private ComparableKey key;
1196        private String JavaDoc one;
1197
1198        private UseComparableKey() { }
1199
1200        private UseComparableKey(ComparableKey key, String JavaDoc one) {
1201            this.key = key;
1202            this.one = one;
1203        }
1204
1205        public Object JavaDoc getPriKeyObject() {
1206            return key;
1207        }
1208
1209        public void validate(Object JavaDoc other) {
1210            UseComparableKey o = (UseComparableKey) other;
1211            TestCase.assertNotNull(key);
1212            TestCase.assertNotNull(o.key);
1213            key.validate(o.key);
1214            TestCase.assertTrue(nullOrEqual(one, o.one));
1215        }
1216    }
1217
1218    public void testSecKeys()
1219        throws DatabaseException {
1220
1221        open();
1222
1223        SecKeys obj = new SecKeys();
1224        checkEntity(SecKeys.class, obj);
1225
1226        checkMetadata(SecKeys.class.getName(), new String JavaDoc[][] {
1227                          {"id", "long"},
1228                          {"f0", "boolean"},
1229                          {"g0", "boolean"},
1230                          {"f1", "char"},
1231                          {"g1", "char"},
1232                          {"f2", "byte"},
1233                          {"g2", "byte"},
1234                          {"f3", "short"},
1235                          {"g3", "short"},
1236                          {"f4", "int"},
1237                          {"g4", "int"},
1238                          {"f5", "long"},
1239                          {"g5", "long"},
1240                          {"f6", "float"},
1241                          {"g6", "float"},
1242                          {"f7", "double"},
1243                          {"g7", "double"},
1244                          {"f8", "java.lang.String"},
1245                          {"g8", "java.lang.String"},
1246                          {"f9", "java.math.BigInteger"},
1247                          {"g9", "java.math.BigInteger"},
1248                          //{"f10", "java.math.BigDecimal"},
1249
//{"g10", "java.math.BigDecimal"},
1250
{"f11", "java.util.Date"},
1251                          {"g11", "java.util.Date"},
1252                          {"f12", "java.lang.Boolean"},
1253                          {"g12", "java.lang.Boolean"},
1254                          {"f13", "java.lang.Character"},
1255                          {"g13", "java.lang.Character"},
1256                          {"f14", "java.lang.Byte"},
1257                          {"g14", "java.lang.Byte"},
1258                          {"f15", "java.lang.Short"},
1259                          {"g15", "java.lang.Short"},
1260                          {"f16", "java.lang.Integer"},
1261                          {"g16", "java.lang.Integer"},
1262                          {"f17", "java.lang.Long"},
1263                          {"g17", "java.lang.Long"},
1264                          {"f18", "java.lang.Float"},
1265                          {"g18", "java.lang.Float"},
1266                          {"f19", "java.lang.Double"},
1267                          {"g19", "java.lang.Double"},
1268                          {"f20", CompositeKey.class.getName()},
1269                          {"g20", CompositeKey.class.getName()},
1270                          {"f21", int[].class.getName()},
1271                          {"g21", int[].class.getName()},
1272                          {"f22", Integer JavaDoc[].class.getName()},
1273                          {"g22", Integer JavaDoc[].class.getName()},
1274                          {"f23", Set JavaDoc.class.getName()},
1275                          {"g23", Set JavaDoc.class.getName()},
1276                          {"f24", CompositeKey[].class.getName()},
1277                          {"g24", CompositeKey[].class.getName()},
1278                          {"f25", Set JavaDoc.class.getName()},
1279                          {"g25", Set JavaDoc.class.getName()},
1280                          {"f31", "java.util.Date"},
1281                          {"f32", "java.lang.Boolean"},
1282                          {"f33", "java.lang.Character"},
1283                          {"f34", "java.lang.Byte"},
1284                          {"f35", "java.lang.Short"},
1285                          {"f36", "java.lang.Integer"},
1286                          {"f37", "java.lang.Long"},
1287                          {"f38", "java.lang.Float"},
1288                          {"f39", "java.lang.Double"},
1289                          {"f40", CompositeKey.class.getName()},
1290                      },
1291                      0 /*priKeyIndex*/, null);
1292
1293        checkSecKey(obj, "f0", obj.f0, Boolean JavaDoc.class);
1294        checkSecKey(obj, "f1", obj.f1, Character JavaDoc.class);
1295        checkSecKey(obj, "f2", obj.f2, Byte JavaDoc.class);
1296        checkSecKey(obj, "f3", obj.f3, Short JavaDoc.class);
1297        checkSecKey(obj, "f4", obj.f4, Integer JavaDoc.class);
1298        checkSecKey(obj, "f5", obj.f5, Long JavaDoc.class);
1299        checkSecKey(obj, "f6", obj.f6, Float JavaDoc.class);
1300        checkSecKey(obj, "f7", obj.f7, Double JavaDoc.class);
1301        checkSecKey(obj, "f8", obj.f8, String JavaDoc.class);
1302        checkSecKey(obj, "f9", obj.f9, BigInteger JavaDoc.class);
1303        //checkSecKey(obj, "f10", obj.f10, BigDecimal.class);
1304
checkSecKey(obj, "f11", obj.f11, Date JavaDoc.class);
1305        checkSecKey(obj, "f12", obj.f12, Boolean JavaDoc.class);
1306        checkSecKey(obj, "f13", obj.f13, Character JavaDoc.class);
1307        checkSecKey(obj, "f14", obj.f14, Byte JavaDoc.class);
1308        checkSecKey(obj, "f15", obj.f15, Short JavaDoc.class);
1309        checkSecKey(obj, "f16", obj.f16, Integer JavaDoc.class);
1310        checkSecKey(obj, "f17", obj.f17, Long JavaDoc.class);
1311        checkSecKey(obj, "f18", obj.f18, Float JavaDoc.class);
1312        checkSecKey(obj, "f19", obj.f19, Double JavaDoc.class);
1313        checkSecKey(obj, "f20", obj.f20, CompositeKey.class);
1314
1315        checkSecMultiKey(obj, "f21", toSet(obj.f21), Integer JavaDoc.class);
1316        checkSecMultiKey(obj, "f22", toSet(obj.f22), Integer JavaDoc.class);
1317        checkSecMultiKey(obj, "f23", toSet(obj.f23), Integer JavaDoc.class);
1318        checkSecMultiKey(obj, "f24", toSet(obj.f24), CompositeKey.class);
1319        checkSecMultiKey(obj, "f25", toSet(obj.f25), CompositeKey.class);
1320
1321        nullifySecKey(obj, "f8", obj.f8, String JavaDoc.class);
1322        nullifySecKey(obj, "f9", obj.f9, BigInteger JavaDoc.class);
1323        //nullifySecKey(obj, "f10", obj.f10, BigDecimal.class);
1324
nullifySecKey(obj, "f11", obj.f11, Date JavaDoc.class);
1325        nullifySecKey(obj, "f12", obj.f12, Boolean JavaDoc.class);
1326        nullifySecKey(obj, "f13", obj.f13, Character JavaDoc.class);
1327        nullifySecKey(obj, "f14", obj.f14, Byte JavaDoc.class);
1328        nullifySecKey(obj, "f15", obj.f15, Short JavaDoc.class);
1329        nullifySecKey(obj, "f16", obj.f16, Integer JavaDoc.class);
1330        nullifySecKey(obj, "f17", obj.f17, Long JavaDoc.class);
1331        nullifySecKey(obj, "f18", obj.f18, Float JavaDoc.class);
1332        nullifySecKey(obj, "f19", obj.f19, Double JavaDoc.class);
1333        nullifySecKey(obj, "f20", obj.f20, CompositeKey.class);
1334
1335        nullifySecMultiKey(obj, "f21", obj.f21, Integer JavaDoc.class);
1336        nullifySecMultiKey(obj, "f22", obj.f22, Integer JavaDoc.class);
1337        nullifySecMultiKey(obj, "f23", obj.f23, Integer JavaDoc.class);
1338        nullifySecMultiKey(obj, "f24", obj.f24, CompositeKey.class);
1339        nullifySecMultiKey(obj, "f25", obj.f25, CompositeKey.class);
1340
1341        nullifySecKey(obj, "f31", obj.f31, Date JavaDoc.class);
1342        nullifySecKey(obj, "f32", obj.f32, Boolean JavaDoc.class);
1343        nullifySecKey(obj, "f33", obj.f33, Character JavaDoc.class);
1344        nullifySecKey(obj, "f34", obj.f34, Byte JavaDoc.class);
1345        nullifySecKey(obj, "f35", obj.f35, Short JavaDoc.class);
1346        nullifySecKey(obj, "f36", obj.f36, Integer JavaDoc.class);
1347        nullifySecKey(obj, "f37", obj.f37, Long JavaDoc.class);
1348        nullifySecKey(obj, "f38", obj.f38, Float JavaDoc.class);
1349        nullifySecKey(obj, "f39", obj.f39, Double JavaDoc.class);
1350        nullifySecKey(obj, "f40", obj.f40, CompositeKey.class);
1351
1352        close();
1353    }
1354
1355    static Set JavaDoc toSet(int[] a) {
1356        Set JavaDoc set = new HashSet JavaDoc();
1357        for (int i : a) {
1358            set.add(i);
1359        }
1360        return set;
1361    }
1362
1363    static Set JavaDoc toSet(Object JavaDoc[] a) {
1364        return new HashSet JavaDoc(Arrays.asList(a));
1365    }
1366
1367    static Set JavaDoc toSet(Set JavaDoc s) {
1368        return s;
1369    }
1370
1371    @Entity
1372    static class SecKeys implements MyEntity {
1373
1374        @PrimaryKey
1375        long id;
1376
1377        @SecondaryKey(relate=MANY_TO_ONE)
1378        private boolean f0 = false;
1379        private boolean g0 = false;
1380
1381        @SecondaryKey(relate=MANY_TO_ONE)
1382        private char f1 = '1';
1383        private char g1 = '1';
1384
1385        @SecondaryKey(relate=MANY_TO_ONE)
1386        private byte f2 = 2;
1387        private byte g2 = 2;
1388
1389        @SecondaryKey(relate=MANY_TO_ONE)
1390        private short f3 = 3;
1391        private short g3 = 3;
1392
1393        @SecondaryKey(relate=MANY_TO_ONE)
1394        private int f4 = 4;
1395        private int g4 = 4;
1396
1397        @SecondaryKey(relate=MANY_TO_ONE)
1398        private long f5 = 5;
1399        private long g5 = 5;
1400
1401        @SecondaryKey(relate=MANY_TO_ONE)
1402        private float f6 = 6.6f;
1403        private float g6 = 6.6f;
1404
1405        @SecondaryKey(relate=MANY_TO_ONE)
1406        private double f7 = 7.7;
1407        private double g7 = 7.7;
1408
1409        @SecondaryKey(relate=MANY_TO_ONE)
1410        private String JavaDoc f8 = "8";
1411        private String JavaDoc g8 = "8";
1412
1413        @SecondaryKey(relate=MANY_TO_ONE)
1414        private BigInteger JavaDoc f9;
1415        private BigInteger JavaDoc g9;
1416
1417        //@SecondaryKey(relate=MANY_TO_ONE)
1418
//private BigDecimal f10;
1419
//private BigDecimal g10;
1420

1421        @SecondaryKey(relate=MANY_TO_ONE)
1422        private Date JavaDoc f11 = new Date JavaDoc(11);
1423        private Date JavaDoc g11 = new Date JavaDoc(11);
1424
1425        @SecondaryKey(relate=MANY_TO_ONE)
1426        private Boolean JavaDoc f12 = true;
1427        private Boolean JavaDoc g12 = true;
1428
1429        @SecondaryKey(relate=MANY_TO_ONE)
1430        private Character JavaDoc f13 = '3';
1431        private Character JavaDoc g13 = '3';
1432
1433        @SecondaryKey(relate=MANY_TO_ONE)
1434        private Byte JavaDoc f14 = 14;
1435        private Byte JavaDoc g14 = 14;
1436
1437        @SecondaryKey(relate=MANY_TO_ONE)
1438        private Short JavaDoc f15 = 15;
1439        private Short JavaDoc g15 = 15;
1440
1441        @SecondaryKey(relate=MANY_TO_ONE)
1442        private Integer JavaDoc f16 = 16;
1443        private Integer JavaDoc g16 = 16;
1444
1445        @SecondaryKey(relate=MANY_TO_ONE)
1446        private Long JavaDoc f17= 17L;
1447        private Long JavaDoc g17= 17L;
1448
1449        @SecondaryKey(relate=MANY_TO_ONE)
1450        private Float JavaDoc f18 = 18.18f;
1451        private Float JavaDoc g18 = 18.18f;
1452
1453        @SecondaryKey(relate=MANY_TO_ONE)
1454        private Double JavaDoc f19 = 19.19;
1455        private Double JavaDoc g19 = 19.19;
1456
1457        @SecondaryKey(relate=MANY_TO_ONE)
1458        private CompositeKey f20 =
1459            new CompositeKey(20, 20L, "20", BigInteger.valueOf(20));
1460        private CompositeKey g20 =
1461            new CompositeKey(20, 20L, "20", BigInteger.valueOf(20));
1462
1463        private static int[] arrayOfInt = { 100, 101, 102 };
1464
1465        private static Integer JavaDoc[] arrayOfInteger = { 100, 101, 102 };
1466
1467        private static CompositeKey[] arrayOfCompositeKey = {
1468            new CompositeKey(100, 100L, "100", BigInteger.valueOf(100)),
1469            new CompositeKey(101, 101L, "101", BigInteger.valueOf(101)),
1470            new CompositeKey(102, 102L, "102", BigInteger.valueOf(102)),
1471        };
1472
1473        @SecondaryKey(relate=ONE_TO_MANY)
1474        private int[] f21 = arrayOfInt;
1475        private int[] g21 = f21;
1476
1477        @SecondaryKey(relate=ONE_TO_MANY)
1478        private Integer JavaDoc[] f22 = arrayOfInteger;
1479        private Integer JavaDoc[] g22 = f22;
1480
1481        @SecondaryKey(relate=ONE_TO_MANY)
1482        private Set JavaDoc<Integer JavaDoc> f23 = toSet(arrayOfInteger);
1483        private Set JavaDoc<Integer JavaDoc> g23 = f23;
1484
1485        @SecondaryKey(relate=ONE_TO_MANY)
1486        private CompositeKey[] f24 = arrayOfCompositeKey;
1487        private CompositeKey[] g24 = f24;
1488
1489        @SecondaryKey(relate=ONE_TO_MANY)
1490        private Set JavaDoc<CompositeKey> f25 = toSet(arrayOfCompositeKey);
1491        private Set JavaDoc<CompositeKey> g25 = f25;
1492
1493        /* Repeated key values to test shared references. */
1494
1495        @SecondaryKey(relate=MANY_TO_ONE)
1496        private Date JavaDoc f31 = f11;
1497
1498        @SecondaryKey(relate=MANY_TO_ONE)
1499        private Boolean JavaDoc f32 = f12;
1500
1501        @SecondaryKey(relate=MANY_TO_ONE)
1502        private Character JavaDoc f33 = f13;
1503
1504        @SecondaryKey(relate=MANY_TO_ONE)
1505        private Byte JavaDoc f34 = f14;
1506
1507        @SecondaryKey(relate=MANY_TO_ONE)
1508        private Short JavaDoc f35 = f15;
1509
1510        @SecondaryKey(relate=MANY_TO_ONE)
1511        private Integer JavaDoc f36 = f16;
1512
1513        @SecondaryKey(relate=MANY_TO_ONE)
1514        private Long JavaDoc f37= f17;
1515
1516        @SecondaryKey(relate=MANY_TO_ONE)
1517        private Float JavaDoc f38 = f18;
1518
1519        @SecondaryKey(relate=MANY_TO_ONE)
1520        private Double JavaDoc f39 = f19;
1521
1522        @SecondaryKey(relate=MANY_TO_ONE)
1523        private CompositeKey f40 = f20;
1524
1525        public Object JavaDoc getPriKeyObject() {
1526            return id;
1527        }
1528
1529        public void validate(Object JavaDoc other) {
1530            SecKeys o = (SecKeys) other;
1531            TestCase.assertEquals(id, o.id);
1532
1533            TestCase.assertEquals(f0, o.f0);
1534            TestCase.assertEquals(f1, o.f1);
1535            TestCase.assertEquals(f2, o.f2);
1536            TestCase.assertEquals(f3, o.f3);
1537            TestCase.assertEquals(f4, o.f4);
1538            TestCase.assertEquals(f5, o.f5);
1539            TestCase.assertEquals(f6, o.f6);
1540            TestCase.assertEquals(f7, o.f7);
1541            TestCase.assertEquals(f8, o.f8);
1542            TestCase.assertEquals(f9, o.f9);
1543            //TestCase.assertEquals(f10, o.f10);
1544
TestCase.assertEquals(f11, o.f11);
1545            TestCase.assertEquals(f12, o.f12);
1546            TestCase.assertEquals(f13, o.f13);
1547            TestCase.assertEquals(f14, o.f14);
1548            TestCase.assertEquals(f15, o.f15);
1549            TestCase.assertEquals(f16, o.f16);
1550            TestCase.assertEquals(f17, o.f17);
1551            TestCase.assertEquals(f18, o.f18);
1552            TestCase.assertEquals(f19, o.f19);
1553            TestCase.assertEquals(f20, o.f20);
1554            TestCase.assertTrue(Arrays.equals(f21, o.f21));
1555            TestCase.assertTrue(Arrays.equals(f22, o.f22));
1556            TestCase.assertEquals(f23, o.f23);
1557            TestCase.assertTrue(Arrays.equals(f24, o.f24));
1558            TestCase.assertEquals(f25, o.f25);
1559
1560            TestCase.assertEquals(g0, o.g0);
1561            TestCase.assertEquals(g1, o.g1);
1562            TestCase.assertEquals(g2, o.g2);
1563            TestCase.assertEquals(g3, o.g3);
1564            TestCase.assertEquals(g4, o.g4);
1565            TestCase.assertEquals(g5, o.g5);
1566            TestCase.assertEquals(g6, o.g6);
1567            TestCase.assertEquals(g7, o.g7);
1568            TestCase.assertEquals(g8, o.g8);
1569            TestCase.assertEquals(g9, o.g9);
1570            //TestCase.assertEquals(g10, o.g10);
1571
TestCase.assertEquals(g11, o.g11);
1572            TestCase.assertEquals(g12, o.g12);
1573            TestCase.assertEquals(g13, o.g13);
1574            TestCase.assertEquals(g14, o.g14);
1575            TestCase.assertEquals(g15, o.g15);
1576            TestCase.assertEquals(g16, o.g16);
1577            TestCase.assertEquals(g17, o.g17);
1578            TestCase.assertEquals(g18, o.g18);
1579            TestCase.assertEquals(g19, o.g19);
1580            TestCase.assertEquals(g20, o.g20);
1581            TestCase.assertTrue(Arrays.equals(g21, o.g21));
1582            TestCase.assertTrue(Arrays.equals(g22, o.g22));
1583            TestCase.assertEquals(g23, o.g23);
1584            TestCase.assertTrue(Arrays.equals(g24, o.g24));
1585            TestCase.assertEquals(g25, o.g25);
1586
1587            TestCase.assertEquals(f31, o.f31);
1588            TestCase.assertEquals(f32, o.f32);
1589            TestCase.assertEquals(f33, o.f33);
1590            TestCase.assertEquals(f34, o.f34);
1591            TestCase.assertEquals(f35, o.f35);
1592            TestCase.assertEquals(f36, o.f36);
1593            TestCase.assertEquals(f37, o.f37);
1594            TestCase.assertEquals(f38, o.f38);
1595            TestCase.assertEquals(f39, o.f39);
1596            TestCase.assertEquals(f40, o.f40);
1597
1598            checkSameIfNonNull(o.f31, o.f11);
1599            checkSameIfNonNull(o.f32, o.f12);
1600            checkSameIfNonNull(o.f33, o.f13);
1601            checkSameIfNonNull(o.f34, o.f14);
1602            checkSameIfNonNull(o.f35, o.f15);
1603            checkSameIfNonNull(o.f36, o.f16);
1604            checkSameIfNonNull(o.f37, o.f17);
1605            checkSameIfNonNull(o.f38, o.f18);
1606            checkSameIfNonNull(o.f39, o.f19);
1607            checkSameIfNonNull(o.f40, o.f20);
1608        }
1609    }
1610
1611    public void testSecKeyRefToPriKey()
1612        throws DatabaseException {
1613
1614        open();
1615
1616        SecKeyRefToPriKey obj = new SecKeyRefToPriKey();
1617        checkEntity(SecKeyRefToPriKey.class, obj);
1618
1619        checkMetadata(SecKeyRefToPriKey.class.getName(), new String JavaDoc[][] {
1620                          {"priKey", "java.lang.String"},
1621                          {"secKey1", "java.lang.String"},
1622                          {"secKey2", String JavaDoc[].class.getName()},
1623                          {"secKey3", Set JavaDoc.class.getName()},
1624                      },
1625                      0 /*priKeyIndex*/, null);
1626
1627        checkSecKey(obj, "secKey1", obj.secKey1, String JavaDoc.class);
1628        checkSecMultiKey(obj, "secKey2", toSet(obj.secKey2), String JavaDoc.class);
1629        checkSecMultiKey(obj, "secKey3", toSet(obj.secKey3), String JavaDoc.class);
1630
1631        close();
1632    }
1633
1634    @Entity
1635    static class SecKeyRefToPriKey implements MyEntity {
1636
1637        @PrimaryKey
1638        private String JavaDoc priKey;
1639
1640        @SecondaryKey(relate=ONE_TO_ONE)
1641        private String JavaDoc secKey1;
1642
1643        @SecondaryKey(relate=ONE_TO_MANY)
1644        private String JavaDoc[] secKey2;
1645
1646        @SecondaryKey(relate=ONE_TO_MANY)
1647        private Set JavaDoc<String JavaDoc> secKey3 = new HashSet JavaDoc<String JavaDoc>();
1648
1649        private SecKeyRefToPriKey() {
1650            priKey = "sharedValue";
1651            secKey1 = priKey;
1652            secKey2 = new String JavaDoc[] { priKey };
1653            secKey3.add(priKey);
1654        }
1655
1656        public Object JavaDoc getPriKeyObject() {
1657            return priKey;
1658        }
1659
1660        public void validate(Object JavaDoc other) {
1661            SecKeyRefToPriKey o = (SecKeyRefToPriKey) other;
1662            TestCase.assertEquals(priKey, o.priKey);
1663            TestCase.assertNotNull(o.secKey1);
1664            TestCase.assertEquals(1, o.secKey2.length);
1665            TestCase.assertEquals(1, o.secKey3.size());
1666            TestCase.assertSame(o.secKey1, o.priKey);
1667            TestCase.assertSame(o.secKey2[0], o.priKey);
1668            TestCase.assertSame(o.secKey3.iterator().next(), o.priKey);
1669        }
1670    }
1671
1672    public void testSecKeyInSuperclass()
1673        throws DatabaseException {
1674
1675        open();
1676
1677        SecKeyInSuperclassEntity obj = new SecKeyInSuperclassEntity();
1678        checkEntity(SecKeyInSuperclassEntity.class, obj);
1679
1680        checkMetadata(SecKeyInSuperclass.class.getName(), new String JavaDoc[][] {
1681                          {"priKey", "java.lang.String"},
1682                          {"secKey1", String JavaDoc.class.getName()},
1683                      },
1684                      0/*priKeyIndex*/, null);
1685
1686        checkMetadata(SecKeyInSuperclassEntity.class.getName(), new String JavaDoc[][] {
1687                          {"secKey2", "java.lang.String"},
1688                      },
1689                      -1 /*priKeyIndex*/, SecKeyInSuperclass.class.getName());
1690
1691        checkSecKey
1692            (obj, SecKeyInSuperclassEntity.class, "secKey1", obj.secKey1,
1693             String JavaDoc.class);
1694        checkSecKey
1695            (obj, SecKeyInSuperclassEntity.class, "secKey2", obj.secKey2,
1696             String JavaDoc.class);
1697
1698        close();
1699    }
1700
1701    @Persistent
1702    static class SecKeyInSuperclass implements MyEntity {
1703
1704        @PrimaryKey
1705        String JavaDoc priKey = "1";
1706
1707        @SecondaryKey(relate=ONE_TO_ONE)
1708        String JavaDoc secKey1 = "1";
1709
1710        public Object JavaDoc getPriKeyObject() {
1711            return priKey;
1712        }
1713
1714        public void validate(Object JavaDoc other) {
1715            SecKeyInSuperclass o = (SecKeyInSuperclass) other;
1716            TestCase.assertEquals(secKey1, o.secKey1);
1717        }
1718    }
1719
1720    @Entity
1721    static class SecKeyInSuperclassEntity extends SecKeyInSuperclass {
1722
1723        @SecondaryKey(relate=ONE_TO_ONE)
1724        String JavaDoc secKey2 = "2";
1725
1726        public void validate(Object JavaDoc other) {
1727            super.validate(other);
1728            SecKeyInSuperclassEntity o = (SecKeyInSuperclassEntity) other;
1729            TestCase.assertEquals(priKey, o.priKey);
1730            TestCase.assertEquals(secKey2, o.secKey2);
1731        }
1732    }
1733
1734    public void testSecKeyInSubclass()
1735        throws DatabaseException {
1736
1737        open();
1738
1739        SecKeyInSubclass obj = new SecKeyInSubclass();
1740        checkEntity(SecKeyInSubclassEntity.class, obj);
1741
1742        checkMetadata(SecKeyInSubclassEntity.class.getName(), new String JavaDoc[][] {
1743                          {"priKey", "java.lang.String"},
1744                          {"secKey1", "java.lang.String"},
1745                      },
1746                      0 /*priKeyIndex*/, null);
1747
1748        checkMetadata(SecKeyInSubclass.class.getName(), new String JavaDoc[][] {
1749                          {"secKey2", String JavaDoc.class.getName()},
1750                      },
1751                      -1 /*priKeyIndex*/,
1752                      SecKeyInSubclassEntity.class.getName());
1753
1754        checkSecKey
1755            (obj, SecKeyInSubclassEntity.class, "secKey1", obj.secKey1,
1756             String JavaDoc.class);
1757        checkSecKey
1758            (obj, SecKeyInSubclassEntity.class, "secKey2", obj.secKey2,
1759             String JavaDoc.class);
1760
1761        close();
1762    }
1763
1764    @Entity
1765    static class SecKeyInSubclassEntity implements MyEntity {
1766
1767        @PrimaryKey
1768        String JavaDoc priKey = "1";
1769
1770        @SecondaryKey(relate=ONE_TO_ONE)
1771        String JavaDoc secKey1;
1772
1773        public Object JavaDoc getPriKeyObject() {
1774            return priKey;
1775        }
1776
1777        public void validate(Object JavaDoc other) {
1778            SecKeyInSubclassEntity o = (SecKeyInSubclassEntity) other;
1779            TestCase.assertEquals(priKey, o.priKey);
1780            TestCase.assertEquals(secKey1, o.secKey1);
1781        }
1782    }
1783
1784    @Persistent
1785    static class SecKeyInSubclass extends SecKeyInSubclassEntity {
1786
1787        @SecondaryKey(relate=ONE_TO_ONE)
1788        String JavaDoc secKey2 = "2";
1789
1790        public void validate(Object JavaDoc other) {
1791            super.validate(other);
1792            SecKeyInSubclass o = (SecKeyInSubclass) other;
1793            TestCase.assertEquals(secKey2, o.secKey2);
1794        }
1795    }
1796
1797    private static void checkSameIfNonNull(Object JavaDoc o1, Object JavaDoc o2) {
1798        if (o1 != null && o2 != null) {
1799            assertSame(o1, o2);
1800        }
1801    }
1802
1803    private void checkEntity(Class JavaDoc entityCls, MyEntity entity)
1804        throws DatabaseException {
1805
1806        Object JavaDoc priKey = entity.getPriKeyObject();
1807        Class JavaDoc keyCls = priKey.getClass();
1808        DatabaseEntry keyEntry2 = new DatabaseEntry();
1809        DatabaseEntry dataEntry2 = new DatabaseEntry();
1810
1811        /* Write object, read it back and validate (compare) it. */
1812        PersistEntityBinding entityBinding =
1813            new PersistEntityBinding(catalog, entityCls.getName(), false);
1814        entityBinding.objectToData(entity, dataEntry);
1815        entityBinding.objectToKey(entity, keyEntry);
1816        Object JavaDoc entity2 = entityBinding.entryToObject(keyEntry, dataEntry);
1817        entity.validate(entity2);
1818
1819        /* Read back the primary key and validate it. */
1820        PersistKeyBinding keyBinding =
1821            new PersistKeyBinding(catalog, keyCls.getName(), false);
1822        Object JavaDoc priKey2 = keyBinding.entryToObject(keyEntry);
1823        assertEquals(priKey, priKey2);
1824        keyBinding.objectToEntry(priKey2, keyEntry2);
1825        assertEquals(keyEntry, keyEntry2);
1826
1827        /* Check raw entity binding. */
1828        PersistEntityBinding rawEntityBinding =
1829            new PersistEntityBinding(catalog, entityCls.getName(), true);
1830        RawObject rawEntity =
1831            (RawObject) rawEntityBinding.entryToObject(keyEntry, dataEntry);
1832        rawEntityBinding.objectToKey(rawEntity, keyEntry2);
1833        rawEntityBinding.objectToData(rawEntity, dataEntry2);
1834        entity2 = entityBinding.entryToObject(keyEntry2, dataEntry2);
1835        entity.validate(entity2);
1836        RawObject rawEntity2 =
1837            (RawObject) rawEntityBinding.entryToObject(keyEntry2, dataEntry2);
1838        assertEquals(rawEntity, rawEntity2);
1839        assertEquals(dataEntry, dataEntry2);
1840        assertEquals(keyEntry, keyEntry2);
1841
1842        /* Check that raw entity can be converted to a regular entity. */
1843        entity2 = catalog.convertRawObject(rawEntity, null);
1844        entity.validate(entity2);
1845
1846        /* Check raw key binding. */
1847        PersistKeyBinding rawKeyBinding =
1848            new PersistKeyBinding(catalog, keyCls.getName(), true);
1849        Object JavaDoc rawKey = rawKeyBinding.entryToObject(keyEntry);
1850        rawKeyBinding.objectToEntry(rawKey, keyEntry2);
1851        priKey2 = keyBinding.entryToObject(keyEntry2);
1852        assertEquals(priKey, priKey2);
1853        assertEquals(keyEntry, keyEntry2);
1854    }
1855    
1856    private void checkSecKey(MyEntity entity,
1857                             String JavaDoc keyName,
1858                             Object JavaDoc keyValue,
1859                             Class JavaDoc keyCls)
1860        throws DatabaseException {
1861        
1862        checkSecKey(entity, entity.getClass(), keyName, keyValue, keyCls);
1863    }
1864    
1865    private void checkSecKey(MyEntity entity,
1866                             Class JavaDoc entityCls,
1867                             String JavaDoc keyName,
1868                             Object JavaDoc keyValue,
1869                             Class JavaDoc keyCls)
1870        throws DatabaseException {
1871        
1872        /* Get entity metadata. */
1873        EntityMetadata entityMeta =
1874            model.getEntityMetadata(entityCls.getName());
1875        assertNotNull(entityMeta);
1876
1877        /* Get secondary key metadata. */
1878        SecondaryKeyMetadata secKeyMeta =
1879            entityMeta.getSecondaryKeys().get(keyName);
1880        assertNotNull(secKeyMeta);
1881        
1882        /* Create key creator/nullifier. */
1883        SecondaryKeyCreator keyCreator = new PersistKeyCreator
1884            (catalog, entityMeta, keyCls.getName(), secKeyMeta);
1885
1886        /* Convert entity to bytes. */
1887        PersistEntityBinding entityBinding =
1888            new PersistEntityBinding(catalog, entityCls.getName(), false);
1889        entityBinding.objectToData(entity, dataEntry);
1890        entityBinding.objectToKey(entity, keyEntry);
1891
1892        /* Extract secondary key bytes from entity bytes. */
1893        DatabaseEntry secKeyEntry = new DatabaseEntry();
1894        boolean isKeyPresent = keyCreator.createSecondaryKey
1895            (null, keyEntry, dataEntry, secKeyEntry);
1896        assertEquals(keyValue != null, isKeyPresent);
1897
1898        /* Convert secondary key bytes back to an object. */
1899        PersistKeyBinding keyBinding =
1900            new PersistKeyBinding(catalog, keyCls.getName(), false);
1901        if (isKeyPresent) {
1902            Object JavaDoc keyValue2 = keyBinding.entryToObject(secKeyEntry);
1903            assertEquals(keyValue, keyValue2);
1904            DatabaseEntry secKeyEntry2 = new DatabaseEntry();
1905            keyBinding.objectToEntry(keyValue2, secKeyEntry2);
1906            assertEquals(secKeyEntry, secKeyEntry2);
1907        }
1908    }
1909    
1910    private void checkSecMultiKey(MyEntity entity,
1911                                  String JavaDoc keyName,
1912                                  Set JavaDoc keyValues,
1913                                  Class JavaDoc keyCls)
1914        throws DatabaseException {
1915        
1916        /* Get entity metadata. */
1917        Class JavaDoc entityCls = entity.getClass();
1918        EntityMetadata entityMeta =
1919            model.getEntityMetadata(entityCls.getName());
1920        assertNotNull(entityMeta);
1921
1922        /* Get secondary key metadata. */
1923        SecondaryKeyMetadata secKeyMeta =
1924            entityMeta.getSecondaryKeys().get(keyName);
1925        assertNotNull(secKeyMeta);
1926        
1927        /* Create key creator/nullifier. */
1928        SecondaryMultiKeyCreator keyCreator = new PersistKeyCreator
1929            (catalog, entityMeta, keyCls.getName(), secKeyMeta);
1930
1931        /* Convert entity to bytes. */
1932        PersistEntityBinding entityBinding =
1933            new PersistEntityBinding(catalog, entityCls.getName(), false);
1934        entityBinding.objectToData(entity, dataEntry);
1935        entityBinding.objectToKey(entity, keyEntry);
1936
1937        /* Extract secondary key bytes from entity bytes. */
1938        Set JavaDoc<DatabaseEntry> results = new HashSet JavaDoc<DatabaseEntry>();
1939        keyCreator.createSecondaryKeys
1940            (null, keyEntry, dataEntry, results);
1941        assertEquals(keyValues.size(), results.size());
1942
1943        /* Convert secondary key bytes back to objects. */
1944        PersistKeyBinding keyBinding =
1945            new PersistKeyBinding(catalog, keyCls.getName(), false);
1946        Set JavaDoc keyValues2 = new HashSet JavaDoc();
1947        for (DatabaseEntry secKeyEntry : results) {
1948            Object JavaDoc keyValue2 = keyBinding.entryToObject(secKeyEntry);
1949            keyValues2.add(keyValue2);
1950        }
1951        assertEquals(keyValues, keyValues2);
1952    }
1953    
1954    private void nullifySecKey(MyEntity entity,
1955                              String JavaDoc keyName,
1956                              Object JavaDoc keyValue,
1957                              Class JavaDoc keyCls)
1958        throws DatabaseException {
1959        
1960        /* Get entity metadata. */
1961        Class JavaDoc entityCls = entity.getClass();
1962        EntityMetadata entityMeta =
1963            model.getEntityMetadata(entityCls.getName());
1964        assertNotNull(entityMeta);
1965
1966        /* Get secondary key metadata. */
1967        SecondaryKeyMetadata secKeyMeta =
1968            entityMeta.getSecondaryKeys().get(keyName);
1969        assertNotNull(secKeyMeta);
1970        
1971        /* Create key creator/nullifier. */
1972        ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator
1973            (catalog, entityMeta, keyCls.getName(), secKeyMeta);
1974
1975        /* Convert entity to bytes. */
1976        PersistEntityBinding entityBinding =
1977            new PersistEntityBinding(catalog, entityCls.getName(), false);
1978        entityBinding.objectToData(entity, dataEntry);
1979        entityBinding.objectToKey(entity, keyEntry);
1980
1981        /* Convert secondary key to bytes. */
1982        PersistKeyBinding keyBinding =
1983            new PersistKeyBinding(catalog, keyCls.getName(), false);
1984        DatabaseEntry secKeyEntry = new DatabaseEntry();
1985        if (keyValue != null) {
1986            keyBinding.objectToEntry(keyValue, secKeyEntry);
1987        }
1988
1989        /* Nullify secondary key bytes within entity bytes. */
1990        boolean isKeyPresent = keyNullifier.nullifyForeignKey
1991            (null, keyEntry, dataEntry, secKeyEntry);
1992        assertEquals(keyValue != null, isKeyPresent);
1993
1994        /* Convert modified entity bytes back to an entity. */
1995        Object JavaDoc entity2 = entityBinding.entryToObject(keyEntry, dataEntry);
1996        setFieldToNull(entity, keyName);
1997        entity.validate(entity2);
1998
1999        /* Do a full check after nullifying it. */
2000        checkSecKey(entity, keyName, null, keyCls);
2001    }
2002    
2003    private void nullifySecMultiKey(MyEntity entity,
2004                                    String JavaDoc keyName,
2005                                    Object JavaDoc keyValue,
2006                                    Class JavaDoc keyCls)
2007        throws DatabaseException {
2008        
2009        /* Get entity metadata. */
2010        Class JavaDoc entityCls = entity.getClass();
2011        EntityMetadata entityMeta =
2012            model.getEntityMetadata(entityCls.getName());
2013        assertNotNull(entityMeta);
2014
2015        /* Get secondary key metadata. */
2016        SecondaryKeyMetadata secKeyMeta =
2017            entityMeta.getSecondaryKeys().get(keyName);
2018        assertNotNull(secKeyMeta);
2019        
2020        /* Create key creator/nullifier. */
2021        ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator
2022            (catalog, entityMeta, keyCls.getName(), secKeyMeta);
2023
2024        /* Convert entity to bytes. */
2025        PersistEntityBinding entityBinding =
2026            new PersistEntityBinding(catalog, entityCls.getName(), false);
2027        entityBinding.objectToData(entity, dataEntry);
2028        entityBinding.objectToKey(entity, keyEntry);
2029
2030        /* Get secondary key binding. */
2031        PersistKeyBinding keyBinding =
2032            new PersistKeyBinding(catalog, keyCls.getName(), false);
2033        DatabaseEntry secKeyEntry = new DatabaseEntry();
2034
2035        /* Nullify one key value at a time until all of them are gone. */
2036        while (true) {
2037            Object JavaDoc fieldObj = getField(entity, keyName);
2038            fieldObj = nullifyFirstElement(fieldObj, keyBinding, secKeyEntry);
2039            if (fieldObj == null) {
2040                break;
2041            }
2042            setField(entity, keyName, fieldObj);
2043
2044            /* Nullify secondary key bytes within entity bytes. */
2045            boolean isKeyPresent = keyNullifier.nullifyForeignKey
2046                (null, keyEntry, dataEntry, secKeyEntry);
2047            assertEquals(keyValue != null, isKeyPresent);
2048
2049            /* Convert modified entity bytes back to an entity. */
2050            Object JavaDoc entity2 = entityBinding.entryToObject(keyEntry, dataEntry);
2051            entity.validate(entity2);
2052
2053            /* Do a full check after nullifying it. */
2054            Set JavaDoc keyValues;
2055            if (fieldObj instanceof Set JavaDoc) {
2056                keyValues = (Set JavaDoc) fieldObj;
2057            } else if (fieldObj instanceof Object JavaDoc[]) {
2058                keyValues = toSet((Object JavaDoc[]) fieldObj);
2059            } else if (fieldObj instanceof int[]) {
2060                keyValues = toSet((int[]) fieldObj);
2061            } else {
2062                throw new IllegalStateException JavaDoc(fieldObj.getClass().getName());
2063            }
2064            checkSecMultiKey(entity, keyName, keyValues, keyCls);
2065        }
2066    }
2067
2068    /**
2069     * Nullifies the first element of an array or collection object by removing
2070     * it from the array or collection. Returns the resulting array or
2071     * collection. Also outputs the removed element to the keyEntry using the
2072     * keyBinding.
2073     */

2074    private Object JavaDoc nullifyFirstElement(Object JavaDoc obj,
2075                                       EntryBinding keyBinding,
2076                                       DatabaseEntry keyEntry) {
2077        if (obj instanceof Collection JavaDoc) {
2078            Iterator JavaDoc i = ((Collection JavaDoc) obj).iterator();
2079            if (i.hasNext()) {
2080                Object JavaDoc elem = i.next();
2081                i.remove();
2082                keyBinding.objectToEntry(elem, keyEntry);
2083                return obj;
2084            } else {
2085                return null;
2086            }
2087        } else if (obj instanceof Object JavaDoc[]) {
2088            Object JavaDoc[] a1 = (Object JavaDoc[]) obj;
2089            if (a1.length > 0) {
2090                Object JavaDoc[] a2 = (Object JavaDoc[]) Array.newInstance
2091                    (obj.getClass().getComponentType(), a1.length - 1);
2092                System.arraycopy(a1, 1, a2, 0, a2.length);
2093                keyBinding.objectToEntry(a1[0], keyEntry);
2094                return a2;
2095            } else {
2096                return null;
2097            }
2098        } else if (obj instanceof int[]) {
2099            int[] a1 = (int[]) obj;
2100            if (a1.length > 0) {
2101                int[] a2 = new int[a1.length - 1];
2102                System.arraycopy(a1, 1, a2, 0, a2.length);
2103                keyBinding.objectToEntry(a1[0], keyEntry);
2104                return a2;
2105            } else {
2106                return null;
2107            }
2108        } else {
2109            throw new IllegalStateException JavaDoc(obj.getClass().getName());
2110        }
2111    }
2112
2113    private void checkMetadata(String JavaDoc clsName,
2114                               String JavaDoc[][] nameTypePairs,
2115                               int priKeyIndex,
2116                               String JavaDoc superClsName)
2117        throws DatabaseException {
2118        
2119        /* Check metadata/types against the live model. */
2120        checkMetadata
2121            (catalog, model, clsName, nameTypePairs, priKeyIndex,
2122             superClsName);
2123
2124        /*
2125         * Open a catalog that uses the stored model.
2126         */

2127        PersistCatalog storedCatalog = new PersistCatalog
2128            (null, env, STORE_PREFIX, "catalog", null, null, null,
2129             false /*useCurrentModel*/, null /*Store*/);
2130        EntityModel storedModel = storedCatalog.getResolvedModel();
2131
2132        /* Check metadata/types against the stored catalog/model. */
2133        checkMetadata
2134            (storedCatalog, storedModel, clsName, nameTypePairs, priKeyIndex,
2135             superClsName);
2136
2137        storedCatalog.close();
2138    }
2139
2140    private void checkMetadata(PersistCatalog checkCatalog,
2141                               EntityModel checkModel,
2142                               String JavaDoc clsName,
2143                               String JavaDoc[][] nameTypePairs,
2144                               int priKeyIndex,
2145                               String JavaDoc superClsName)
2146        throws DatabaseException {
2147
2148        ClassMetadata classMeta = checkModel.getClassMetadata(clsName);
2149        assertNotNull(clsName, classMeta);
2150
2151        PrimaryKeyMetadata priKeyMeta = classMeta.getPrimaryKey();
2152        if (priKeyIndex >= 0) {
2153            assertNotNull(priKeyMeta);
2154            String JavaDoc fieldName = nameTypePairs[priKeyIndex][0];
2155            String JavaDoc fieldType = nameTypePairs[priKeyIndex][1];
2156            assertEquals(priKeyMeta.getName(), fieldName);
2157            assertEquals(priKeyMeta.getClassName(), fieldType);
2158            assertEquals(priKeyMeta.getDeclaringClassName(), clsName);
2159            assertNull(priKeyMeta.getSequenceName());
2160        } else {
2161            assertNull(priKeyMeta);
2162        }
2163
2164        RawType type = checkCatalog.getFormat(clsName);
2165        assertNotNull(type);
2166        assertEquals(clsName, type.getClassName());
2167        assertEquals(0, type.getVersion());
2168        assertTrue(!type.isSimple());
2169        assertTrue(!type.isPrimitive());
2170        assertTrue(!type.isEnum());
2171        assertNull(type.getEnumConstants());
2172        assertTrue(!type.isArray());
2173        assertEquals(0, type.getDimensions());
2174        assertNull(type.getComponentType());
2175        RawType superType = type.getSuperType();
2176        if (superClsName != null) {
2177            assertNotNull(superType);
2178            assertEquals(superClsName, superType.getClassName());
2179        } else {
2180            assertNull(superType);
2181        }
2182
2183        Map JavaDoc<String JavaDoc,RawField> fields = type.getFields();
2184        assertNotNull(fields);
2185
2186        int nFields = nameTypePairs.length;
2187        assertEquals(nFields, fields.size());
2188
2189        for (String JavaDoc[] pair : nameTypePairs) {
2190            String JavaDoc fieldName = pair[0];
2191            String JavaDoc fieldType = pair[1];
2192            Class JavaDoc fieldCls;
2193            try {
2194                fieldCls = SimpleCatalog.classForName(fieldType);
2195            } catch (ClassNotFoundException JavaDoc e) {
2196                fail(e.toString());
2197                return; /* For compiler */
2198            }
2199            RawField field = fields.get(fieldName);
2200            assertNotNull(field);
2201            assertEquals(fieldName, field.getName());
2202            type = field.getType();
2203            assertNotNull(type);
2204            int dim = getArrayDimensions(fieldType);
2205            while (dim > 0) {
2206                assertEquals(dim, type.getDimensions());
2207                assertEquals(dim, getArrayDimensions(fieldType));
2208                assertEquals(true, type.isArray());
2209                assertEquals(fieldType, type.getClassName());
2210                assertEquals(0, type.getVersion());
2211                assertTrue(!type.isSimple());
2212                assertTrue(!type.isPrimitive());
2213                assertTrue(!type.isEnum());
2214                assertNull(type.getEnumConstants());
2215                fieldType = getArrayComponent(fieldType, dim);
2216                type = type.getComponentType();
2217                assertNotNull(fieldType, type);
2218                dim -= 1;
2219            }
2220            assertEquals(fieldType, type.getClassName());
2221            List JavaDoc<String JavaDoc> enums = getEnumConstants(fieldType);
2222            assertEquals(isSimpleType(fieldType), type.isSimple());
2223            assertEquals(isPrimitiveType(fieldType), type.isPrimitive());
2224            assertNull(type.getComponentType());
2225            assertTrue(!type.isArray());
2226            assertEquals(0, type.getDimensions());
2227            if (enums != null) {
2228                assertTrue(type.isEnum());
2229                assertEquals(enums, type.getEnumConstants());
2230                assertNull(type.getSuperType());
2231            } else {
2232                assertTrue(!type.isEnum());
2233                assertNull(type.getEnumConstants());
2234            }
2235        }
2236    }
2237
2238    private List JavaDoc<String JavaDoc> getEnumConstants(String JavaDoc clsName) {
2239        if (isPrimitiveType(clsName)) {
2240            return null;
2241        }
2242        Class JavaDoc cls;
2243        try {
2244            cls = Class.forName(clsName);
2245        } catch (ClassNotFoundException JavaDoc e) {
2246            fail(e.toString());
2247            return null; /* Never happens. */
2248        }
2249        if (!cls.isEnum()) {
2250            return null;
2251        }
2252        List JavaDoc<String JavaDoc> enums = new ArrayList JavaDoc<String JavaDoc>();
2253        Object JavaDoc[] vals = cls.getEnumConstants();
2254        for (Object JavaDoc val : vals) {
2255            enums.add(val.toString());
2256        }
2257        return enums;
2258    }
2259
2260    private String JavaDoc getArrayComponent(String JavaDoc clsName, int dim) {
2261        clsName = clsName.substring(1);
2262        if (dim > 1) {
2263            return clsName;
2264        }
2265        if (clsName.charAt(0) == 'L' &&
2266            clsName.charAt(clsName.length() - 1) == ';') {
2267            return clsName.substring(1, clsName.length() - 1);
2268        }
2269        if (clsName.length() != 1) {
2270            fail();
2271        }
2272        switch (clsName.charAt(0)) {
2273        case 'Z': return "boolean";
2274        case 'B': return "byte";
2275        case 'C': return "char";
2276        case 'D': return "double";
2277        case 'F': return "float";
2278        case 'I': return "int";
2279        case 'J': return "long";
2280        case 'S': return "short";
2281        default: fail();
2282        }
2283        return null; /* Should never happen. */
2284    }
2285
2286    private static int getArrayDimensions(String JavaDoc clsName) {
2287        int i = 0;
2288        while (clsName.charAt(i) == '[') {
2289            i += 1;
2290        }
2291        return i;
2292    }
2293
2294    private static boolean isSimpleType(String JavaDoc clsName) {
2295        return isPrimitiveType(clsName) ||
2296               clsName.equals("java.lang.Boolean") ||
2297               clsName.equals("java.lang.Character") ||
2298               clsName.equals("java.lang.Byte") ||
2299               clsName.equals("java.lang.Short") ||
2300               clsName.equals("java.lang.Integer") ||
2301               clsName.equals("java.lang.Long") ||
2302               clsName.equals("java.lang.Float") ||
2303               clsName.equals("java.lang.Double") ||
2304               clsName.equals("java.lang.String") ||
2305               clsName.equals("java.math.BigInteger") ||
2306               //clsName.equals("java.math.BigDecimal") ||
2307
clsName.equals("java.util.Date");
2308    }
2309
2310    private static boolean isPrimitiveType(String JavaDoc clsName) {
2311        return clsName.equals("boolean") ||
2312               clsName.equals("char") ||
2313               clsName.equals("byte") ||
2314               clsName.equals("short") ||
2315               clsName.equals("int") ||
2316               clsName.equals("long") ||
2317               clsName.equals("float") ||
2318               clsName.equals("double");
2319    }
2320
2321    interface MyEntity {
2322        Object JavaDoc getPriKeyObject();
2323        void validate(Object JavaDoc other);
2324    }
2325
2326    private static boolean nullOrEqual(Object JavaDoc o1, Object JavaDoc o2) {
2327        return (o1 != null) ? o1.equals(o2) : (o2 == null);
2328    }
2329
2330    private static String JavaDoc arrayToString(Object JavaDoc[] array) {
2331        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2332        buf.append('[');
2333        for (Object JavaDoc o : array) {
2334            if (o instanceof Object JavaDoc[]) {
2335                buf.append(arrayToString((Object JavaDoc[]) o));
2336            } else {
2337                buf.append(o);
2338            }
2339            buf.append(',');
2340        }
2341        buf.append(']');
2342        return buf.toString();
2343    }
2344
2345    private void setFieldToNull(Object JavaDoc obj, String JavaDoc fieldName) {
2346        try {
2347            Field JavaDoc field = obj.getClass().getDeclaredField(fieldName);
2348            field.setAccessible(true);
2349            field.set(obj, null);
2350        } catch (NoSuchFieldException JavaDoc e) {
2351            fail(e.toString());
2352        } catch (IllegalAccessException JavaDoc e) {
2353            fail(e.toString());
2354        }
2355    }
2356
2357    private void setField(Object JavaDoc obj, String JavaDoc fieldName, Object JavaDoc fieldValue) {
2358        try {
2359            Field JavaDoc field = obj.getClass().getDeclaredField(fieldName);
2360            field.setAccessible(true);
2361            field.set(obj, fieldValue);
2362        } catch (NoSuchFieldException JavaDoc e) {
2363            throw new IllegalStateException JavaDoc(e.toString());
2364        } catch (IllegalAccessException JavaDoc e) {
2365            throw new IllegalStateException JavaDoc(e.toString());
2366        }
2367    }
2368
2369    private Object JavaDoc getField(Object JavaDoc obj, String JavaDoc fieldName) {
2370        try {
2371            Field JavaDoc field = obj.getClass().getDeclaredField(fieldName);
2372            field.setAccessible(true);
2373            return field.get(obj);
2374        } catch (NoSuchFieldException JavaDoc e) {
2375            throw new IllegalStateException JavaDoc(e.toString());
2376        } catch (IllegalAccessException JavaDoc e) {
2377            throw new IllegalStateException JavaDoc(e.toString());
2378        }
2379    }
2380}
2381
Popular Tags