KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > je > ToManyExample


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2004,2006 Oracle. All rights reserved.
5  *
6  * $Id: ToManyExample.java,v 1.5 2006/10/30 21:14:04 bostic Exp $
7  */

8
9 package je;
10
11 import java.io.File JavaDoc;
12 import java.io.Serializable JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Set JavaDoc;
16
17 import com.sleepycat.bind.EntryBinding;
18 import com.sleepycat.bind.serial.SerialBinding;
19 import com.sleepycat.bind.serial.StoredClassCatalog;
20 import com.sleepycat.bind.tuple.StringBinding;
21 import com.sleepycat.je.Database;
22 import com.sleepycat.je.DatabaseConfig;
23 import com.sleepycat.je.DatabaseEntry;
24 import com.sleepycat.je.DatabaseException;
25 import com.sleepycat.je.Environment;
26 import com.sleepycat.je.EnvironmentConfig;
27 import com.sleepycat.je.ForeignKeyDeleteAction;
28 import com.sleepycat.je.ForeignMultiKeyNullifier;
29 import com.sleepycat.je.OperationStatus;
30 import com.sleepycat.je.SecondaryConfig;
31 import com.sleepycat.je.SecondaryCursor;
32 import com.sleepycat.je.SecondaryDatabase;
33 import com.sleepycat.je.SecondaryMultiKeyCreator;
34 import com.sleepycat.je.Transaction;
35
36 /**
37  * An example of using many-to-many and one-to-many secondary indices.
38  */

39 public class ToManyExample {
40
41     private Environment env;
42     private Database catalogDb;
43     private Database animalDb;
44     private Database personDb;
45     private SecondaryDatabase personByEmail;
46     private SecondaryDatabase personByAnimal;
47     private EntryBinding keyBinding;
48     private EntryBinding dataBinding;
49
50     /**
51      * Runs the example program, given a single "-h HOME" argument.
52      */

53     public static void main(String JavaDoc[] args) {
54
55         if (args.length != 2 || !"-h".equals(args[0])) {
56             System.out.println("Usage: java " +
57                                ToManyExample.class.getName() +
58                                " -h ENV_HOME");
59             System.exit(1);
60         }
61         String JavaDoc homeDir = args[1];
62
63         try {
64             ToManyExample example = new ToManyExample(homeDir);
65             example.exec();
66             example.close();
67         } catch (DatabaseException e) {
68             e.printStackTrace();
69         }
70     }
71
72     /**
73      * Opens the environment and all databases.
74      */

75     private ToManyExample(String JavaDoc homeDir) throws DatabaseException {
76
77         /* Open the environment. */
78         EnvironmentConfig envConfig = new EnvironmentConfig();
79         envConfig.setAllowCreate(true);
80         envConfig.setTransactional(true);
81         env = new Environment(new File JavaDoc(homeDir), envConfig);
82
83         /* Open/create all databases in a transaction. */
84         Transaction txn = env.beginTransaction(null, null);
85         try {
86             /* A standard (no duplicates) database config. */
87             DatabaseConfig dbConfig = new DatabaseConfig();
88             dbConfig.setAllowCreate(true);
89             dbConfig.setTransactional(true);
90
91             /* The catalog is used for the serial binding. */
92             catalogDb = env.openDatabase(txn, "catalog", dbConfig);
93             StoredClassCatalog catalog = new StoredClassCatalog(catalogDb);
94             dataBinding = new SerialBinding(catalog, null);
95             keyBinding = new StringBinding();
96
97             /* Open the person and animal primary DBs. */
98             animalDb = env.openDatabase(txn, "animal", dbConfig);
99             personDb = env.openDatabase(txn, "person", dbConfig);
100
101             /*
102              * A standard secondary config; duplicates, key creators and key
103              * nullifiers are specified below.
104              */

105             SecondaryConfig secConfig = new SecondaryConfig();
106             secConfig.setAllowCreate(true);
107             secConfig.setTransactional(true);
108
109             /*
110              * Open the secondary database for personByEmail. This is a
111              * one-to-many index because duplicates are not configured.
112              */

113             secConfig.setSortedDuplicates(false);
114             secConfig.setMultiKeyCreator(new EmailKeyCreator());
115             personByEmail = env.openSecondaryDatabase(txn, "personByEmail",
116                                                       personDb, secConfig);
117
118             /*
119              * Open the secondary database for personByAnimal. This is a
120              * many-to-many index because duplicates are configured. Foreign
121              * key constraints are specified to ensure that all animal keys
122              * exist in the animal database.
123              */

124             secConfig.setSortedDuplicates(true);
125             secConfig.setMultiKeyCreator(new AnimalKeyCreator());
126             secConfig.setForeignMultiKeyNullifier(new AnimalKeyNullifier());
127             secConfig.setForeignKeyDatabase(animalDb);
128             secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.NULLIFY);
129             personByAnimal = env.openSecondaryDatabase(txn, "personByAnimal",
130                                                        personDb, secConfig);
131
132             txn.commit();
133         } catch (DatabaseException e) {
134             txn.abort();
135             throw e;
136         } catch (RuntimeException JavaDoc e) {
137             txn.abort();
138             throw e;
139         }
140     }
141
142     /**
143      * Closes all databases and the environment.
144      */

145     private void close() throws DatabaseException {
146
147         if (personByEmail != null) {
148             personByEmail.close();
149         }
150         if (personByAnimal != null) {
151             personByAnimal.close();
152         }
153         if (catalogDb != null) {
154             catalogDb.close();
155         }
156         if (personDb != null) {
157             personDb.close();
158         }
159         if (animalDb != null) {
160             animalDb.close();
161         }
162         if (env != null) {
163             env.close();
164         }
165     }
166
167     /**
168      * Adds, updates, prints and deletes Person records with many-to-many and
169      * one-to-many secondary indices.
170      */

171     private void exec()
172         throws DatabaseException {
173
174         System.out.println
175             ("\nInsert some animals.");
176         Animal dogs = insertAndPrintAnimal("dogs", true);
177         Animal fish = insertAndPrintAnimal("fish", false);
178         Animal horses = insertAndPrintAnimal("horses", true);
179         Animal donkeys = insertAndPrintAnimal("donkeys", true);
180
181         System.out.println
182             ("\nInsert a new empty person.");
183         Person kathy = new Person();
184         kathy.name = "Kathy";
185         putPerson(kathy);
186         printPerson("Kathy");
187
188         System.out.println
189             ("\nAdd favorites/addresses and update the record.");
190         kathy.favoriteAnimals.add(horses.name);
191         kathy.favoriteAnimals.add(dogs.name);
192         kathy.favoriteAnimals.add(fish.name);
193         kathy.emailAddresses.add("kathy@kathy.com");
194         kathy.emailAddresses.add("kathy@yahoo.com");
195         putPerson(kathy);
196         printPerson("Kathy");
197
198         System.out.println
199             ("\nChange favorites and addresses and update the person record.");
200         kathy.favoriteAnimals.remove(fish.name);
201         kathy.favoriteAnimals.add(donkeys.name);
202         kathy.emailAddresses.add("kathy@gmail.com");
203         kathy.emailAddresses.remove("kathy@yahoo.com");
204         putPerson(kathy);
205         printPerson("Kathy");
206
207         System.out.println
208             ("\nInsert another person with some of the same favorites.");
209         Person mark = new Person();
210         mark.favoriteAnimals.add(dogs.name);
211         mark.favoriteAnimals.add(horses.name);
212         mark.name = "Mark";
213         putPerson(mark);
214         printPerson("Mark");
215
216         System.out.println
217             ("\nPrint by favorite animal index.");
218         printByIndex(personByAnimal);
219
220         System.out.println
221             ("\nPrint by email address index.");
222         printByIndex(personByEmail);
223
224         System.out.println
225             ("\nDelete 'dogs' and print again by favorite animal index.");
226         deleteAnimal(dogs.name);
227         printPerson("Kathy");
228         printPerson("Mark");
229         printByIndex(personByAnimal);
230
231         System.out.println
232             ("\nDelete both records and print again (should print nothing).");
233         deletePerson("Kathy");
234         deletePerson("Mark");
235         printPerson("Kathy");
236         printPerson("Mark");
237         printByIndex(personByAnimal);
238         printByIndex(personByEmail);
239     }
240
241     /**
242      * Inserts an animal record and prints it. Uses auto-commit.
243      */

244     private Animal insertAndPrintAnimal(String JavaDoc name, boolean furry)
245         throws DatabaseException {
246         
247         Animal animal = new Animal();
248         animal.name = name;
249         animal.furry = furry;
250
251         DatabaseEntry key = new DatabaseEntry();
252         keyBinding.objectToEntry(name, key);
253
254         DatabaseEntry data = new DatabaseEntry();
255         dataBinding.objectToEntry(animal, data);
256
257         OperationStatus status = animalDb.putNoOverwrite(null, key, data);
258         if (status == OperationStatus.SUCCESS) {
259             System.out.println(animal);
260         } else {
261             System.out.println("Animal was not inserted: " + name +
262                                " (" + status + ')');
263         }
264
265         return animal;
266     }
267
268     /**
269      * Deletes an animal. Uses auto-commit.
270      */

271     private boolean deleteAnimal(String JavaDoc name)
272         throws DatabaseException {
273         
274         DatabaseEntry key = new DatabaseEntry();
275         keyBinding.objectToEntry(name, key);
276
277         OperationStatus status = animalDb.delete(null, key);
278         return status == OperationStatus.SUCCESS;
279     }
280
281     /**
282      * Gets a person by name and prints it.
283      */

284     private void printPerson(String JavaDoc name)
285         throws DatabaseException {
286         
287         DatabaseEntry key = new DatabaseEntry();
288         keyBinding.objectToEntry(name, key);
289
290         DatabaseEntry data = new DatabaseEntry();
291
292         OperationStatus status = personDb.get(null, key, data, null);
293         if (status == OperationStatus.SUCCESS) {
294             Person person = (Person) dataBinding.entryToObject(data);
295             person.name = (String JavaDoc) keyBinding.entryToObject(key);
296             System.out.println(person);
297         } else {
298             System.out.println("Person not found: " + name);
299         }
300     }
301
302     /**
303      * Prints all person records by a given secondary index.
304      */

305     private void printByIndex(SecondaryDatabase secDb)
306         throws DatabaseException {
307
308         DatabaseEntry secKey = new DatabaseEntry();
309         DatabaseEntry priKey = new DatabaseEntry();
310         DatabaseEntry priData = new DatabaseEntry();
311
312         SecondaryCursor cursor = secDb.openSecondaryCursor(null, null);
313         try {
314             while (cursor.getNext(secKey, priKey, priData, null) ==
315                    OperationStatus.SUCCESS) {
316                 Person person = (Person) dataBinding.entryToObject(priData);
317                 person.name = (String JavaDoc) keyBinding.entryToObject(priKey);
318                 System.out.println("Index key [" +
319                                    keyBinding.entryToObject(secKey) +
320                                    "] maps to primary key [" +
321                                    person.name + ']');
322             }
323         } finally {
324             cursor.close();
325         }
326     }
327
328     /**
329      * Inserts or updates a person. Uses auto-commit.
330      */

331     private void putPerson(Person person)
332         throws DatabaseException {
333         
334         DatabaseEntry key = new DatabaseEntry();
335         keyBinding.objectToEntry(person.name, key);
336
337         DatabaseEntry data = new DatabaseEntry();
338         dataBinding.objectToEntry(person, data);
339
340         personDb.put(null, key, data);
341     }
342
343     /**
344      * Deletes a person. Uses auto-commit.
345      */

346     private boolean deletePerson(String JavaDoc name)
347         throws DatabaseException {
348         
349         DatabaseEntry key = new DatabaseEntry();
350         keyBinding.objectToEntry(name, key);
351
352         OperationStatus status = personDb.delete(null, key);
353         return status == OperationStatus.SUCCESS;
354     }
355
356     /**
357      * A person object.
358      */

359     private static class Person implements Serializable JavaDoc {
360
361         /** The primary key. */
362         private transient String JavaDoc name;
363
364         /** A many-to-many set of keys. */
365         private Set JavaDoc favoriteAnimals = new HashSet JavaDoc();
366
367         /** A one-to-many set of keys. */
368         private Set JavaDoc emailAddresses = new HashSet JavaDoc();
369
370         public String JavaDoc toString() {
371             return "Person {" +
372                    "\n Name: " + name +
373                    "\n FavoriteAnimals: " + favoriteAnimals +
374                    "\n EmailAddresses: " + emailAddresses +
375                    "\n}";
376         }
377     }
378
379     /**
380      * An animal object.
381      */

382     private static class Animal implements Serializable JavaDoc {
383
384         /** The primary key. */
385         private transient String JavaDoc name;
386
387         /** A non-indexed property. */
388         private boolean furry;
389
390         public String JavaDoc toString() {
391             return "Animal {" +
392                    "\n Name: " + name +
393                    "\n Furry: " + furry +
394                    "\n}";
395         }
396     }
397
398     /**
399      * Returns the set of email addresses for a person. This is an example
400      * of a multi-key creator for a to-many index.
401      */

402     private class EmailKeyCreator implements SecondaryMultiKeyCreator {
403
404         public void createSecondaryKeys(SecondaryDatabase secondary,
405                                         DatabaseEntry primaryKey,
406                                         DatabaseEntry primaryData,
407                                         Set JavaDoc results)
408             throws DatabaseException {
409
410             Person person = (Person) dataBinding.entryToObject(primaryData);
411             copyKeysToEntries(person.emailAddresses, results);
412         }
413     }
414
415     /**
416      * Returns the set of favorite animals for a person. This is an example
417      * of a multi-key creator for a to-many index.
418      */

419     private class AnimalKeyCreator implements SecondaryMultiKeyCreator {
420
421         public void createSecondaryKeys(SecondaryDatabase secondary,
422                                         DatabaseEntry primaryKey,
423                                         DatabaseEntry primaryData,
424                                         Set JavaDoc results)
425             throws DatabaseException {
426
427             Person person = (Person) dataBinding.entryToObject(primaryData);
428             copyKeysToEntries(person.favoriteAnimals, results);
429         }
430     }
431
432     /**
433      * A utility method to copy a set of keys (Strings) into a set of
434      * DatabaseEntry objects.
435      */

436     private void copyKeysToEntries(Set JavaDoc keys, Set JavaDoc entries) {
437
438         for (Iterator JavaDoc i = keys.iterator(); i.hasNext();) {
439             DatabaseEntry entry = new DatabaseEntry();
440             keyBinding.objectToEntry(i.next(), entry);
441             entries.add(entry);
442         }
443     }
444
445     /**
446      * Removes a given key from the set of favorite animals for a person. This
447      * is an example of a nullifier for a to-many index. The nullifier is
448      * called when an animal record is deleted because we configured this
449      * secondary with ForeignKeyDeleteAction.NULLIFY.
450      */

451     private class AnimalKeyNullifier implements ForeignMultiKeyNullifier {
452
453         public boolean nullifyForeignKey(SecondaryDatabase secondary,
454                                          DatabaseEntry primaryKey,
455                                          DatabaseEntry primaryData,
456                                          DatabaseEntry secKey)
457             throws DatabaseException {
458
459             Person person = (Person) dataBinding.entryToObject(primaryData);
460             String JavaDoc key = (String JavaDoc) keyBinding.entryToObject(secKey);
461             if (person.favoriteAnimals.remove(key)) {
462                 dataBinding.objectToEntry(person, primaryData);
463                 return true;
464             } else {
465                 return false;
466             }
467         }
468     }
469 }
470
Popular Tags