001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: SecondaryIndex.java,v 1.14.2.3 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.persist;
010:
011: import java.util.Map;
012: import java.util.SortedMap;
013:
014: import com.sleepycat.bind.EntityBinding;
015: import com.sleepycat.bind.EntryBinding;
016: import com.sleepycat.collections.StoredSortedMap;
017: import com.sleepycat.je.Database;
018: import com.sleepycat.je.DatabaseConfig;
019: import com.sleepycat.je.DatabaseEntry;
020: import com.sleepycat.je.DatabaseException;
021: import com.sleepycat.je.LockMode;
022: import com.sleepycat.je.OperationStatus;
023: import com.sleepycat.je.SecondaryDatabase;
024: import com.sleepycat.je.Transaction;
025: import com.sleepycat.persist.model.DeleteAction;
026: import com.sleepycat.persist.model.Relationship;
027: import com.sleepycat.persist.model.SecondaryKey;
028:
029: /**
030: * The secondary index for an entity class and a secondary key.
031: *
032: * <p>{@code SecondaryIndex} objects are thread-safe. Multiple threads may
033: * safely call the methods of a shared {@code SecondaryIndex} object.</p>
034: *
035: * <p>{@code SecondaryIndex} implements {@link EntityIndex} to map the
036: * secondary key type (SK) to the entity type (E). In other words, entities
037: * are accessed by secondary key values.</p>
038: *
039: * <p>The {@link SecondaryKey} annotation may be used to define a secondary key
040: * as shown in the following example.</p>
041: *
042: * <pre class="code">
043: * {@literal @Entity}
044: * class Employee {
045: *
046: * {@literal @PrimaryKey}
047: * long id;
048: *
049: * {@literal @SecondaryKey(relate=MANY_TO_ONE)}
050: * String department;
051: *
052: * String name;
053: *
054: * private Employee() {}
055: * }</pre>
056: *
057: * <p>Before obtaining a {@code SecondaryIndex}, the {@link PrimaryIndex} must
058: * be obtained for the entity class. To obtain the {@code SecondaryIndex} call
059: * {@link EntityStore#getSecondaryIndex EntityStore.getSecondaryIndex}, passing
060: * the primary index, the secondary key class and the secondary key name. For
061: * example:</p>
062: *
063: * <pre class="code">
064: * EntityStore store = new EntityStore(...);
065: *
066: * {@code PrimaryIndex<Long,Employee>} primaryIndex =
067: * store.getPrimaryIndex(Long.class, Employee.class);
068: *
069: * {@code SecondaryIndex<String,Long,Employee>} secondaryIndex =
070: * store.getSecondaryIndex(primaryIndex, String.class, "department");</pre>
071: *
072: * <p>Since {@code SecondaryIndex} implements the {@link EntityIndex}
073: * interface, it shares the common index methods for retrieving and deleting
074: * entities, opening cursors and using transactions. See {@link EntityIndex}
075: * for more information on these topics.</p>
076: *
077: * <p>{@code SecondaryIndex} does <em>not</em> provide methods for inserting
078: * and updating entities. That must be done using the {@link
079: * PrimaryIndex}.</p>
080: *
081: * <p>Note that a {@code SecondaryIndex} has three type parameters {@code
082: * <SK,PK,E>} or in the example {@code <String,Long,Employee>} while a {@link
083: * PrimaryIndex} has only two type parameters {@code <PK,E>} or {@code
084: * <Long,Employee>}. This is because a {@code SecondaryIndex} has an extra
085: * level of mapping: It maps from secondary key to primary key, and then from
086: * primary key to entity. For example, consider this entity:</p>
087: *
088: * <p><table class="code" border="1">
089: * <tr><th>ID</th><th>Department</th><th>Name</th></tr>
090: * <tr><td>1</td><td>Engineering</td><td>Jane Smith</td></tr>
091: * </table></p>
092: *
093: * <p>The {@link PrimaryIndex} maps from id directly to the entity, or from
094: * primary key 1 to the "Jane Smith" entity in the example. The {@code
095: * SecondaryIndex} maps from department to id, or from secondary key
096: * "Engineering" to primary key 1 in the example, and then uses the {@code
097: * PrimaryIndex} to map from the primary key to the entity.</p>
098: *
099: * <p>Because of this extra type parameter and extra level of mapping, a {@code
100: * SecondaryIndex} can provide more than one mapping, or view, of the entities
101: * in the primary index. The main mapping of a {@code SecondaryIndex} is to
102: * map from secondary key (SK) to entity (E), or in the example, from the
103: * String department key to the Employee entity. The {@code SecondaryIndex}
104: * itself, by implementing {@code EntityIndex<SK,E>}, provides this
105: * mapping.</p>
106: *
107: * <p>The second mapping provided by {@code SecondaryIndex} is from secondary
108: * key (SK) to primary key (PK), or in the example, from the String department
109: * key to the Long id key. The {@link #keysIndex} method provides this
110: * mapping. When accessing the keys index, the primary key is returned rather
111: * than the entity. When only the primary key is needed and not the entire
112: * entity, using the keys index is less expensive than using the secondary
113: * index because the primary index does not have to be accessed.</p>
114: *
115: * <p>The third mapping provided by {@code SecondaryIndex} is from primary key
116: * (PK) to entity (E), for the subset of entities having a given secondary key
117: * (SK). This mapping is provided by the {@link #subIndex} method. A
118: * sub-index is convenient when you are interested in working with the subset
119: * of entities having a particular secondary key value, for example, all
120: * employees in a given department.</p>
121: *
122: * <p>All three mappings, along with the mapping provided by the {@link
123: * PrimaryIndex}, are shown using example data in the {@link EntityIndex}
124: * interface documentation. See {@link EntityIndex} for more information.</p>
125: *
126: * <p>Note that when using an index, keys and values are stored and retrieved
127: * by value not by reference. In other words, if an entity object is stored
128: * and then retrieved, or retrieved twice, each object will be a separate
129: * instance. For example, in the code below the assertion will always
130: * fail.</p>
131: * <pre class="code">
132: * MyKey key = ...;
133: * MyEntity entity1 = index.get(key);
134: * MyEntity entity2 = index.get(key);
135: * assert entity1 == entity2; // always fails!
136: * </pre>
137: *
138: * <h3>One-to-One Relationships</h3>
139: *
140: * <p>A {@link Relationship#ONE_TO_ONE ONE_TO_ONE} relationship, although less
141: * common than other types of relationships, is the simplest type of
142: * relationship. A single entity is related to a single secondary key value.
143: * For example:</p>
144: *
145: * <pre class="code">
146: * {@literal @Entity}
147: * class Employee {
148: *
149: * {@literal @PrimaryKey}
150: * long id;
151: *
152: * {@literal @SecondaryKey(relate=ONE_TO_ONE)}
153: * String ssn;
154: *
155: * String name;
156: *
157: * private Employee() {}
158: * }
159: *
160: * {@code SecondaryIndex<String,Long,Employee>} employeeBySsn =
161: * store.getSecondaryIndex(primaryIndex, String.class, "ssn");</pre>
162: *
163: * <p>With a {@link Relationship#ONE_TO_ONE ONE_TO_ONE} relationship, the
164: * secondary key must be unique; in other words, no two entities may have the
165: * same secondary key value. If an attempt is made to store an entity having
166: * the same secondary key value as another existing entity, a {@link
167: * DatabaseException} will be thrown.</p>
168: *
169: * <p>Because the secondary key is unique, it is useful to lookup entities by
170: * secondary key using {@link EntityIndex#get}. For example:</p>
171: *
172: * <pre class="code">
173: * Employee employee = employeeBySsn.get(mySsn);</pre>
174: *
175: * <h3>Many-to-One Relationships</h3>
176: *
177: * <p>A {@link Relationship#MANY_TO_ONE MANY_TO_ONE} relationship is the most
178: * common type of relationship. One or more entities is related to a single
179: * secondary key value. For example:</p>
180: *
181: * <pre class="code">
182: * {@literal @Entity}
183: * class Employee {
184: *
185: * {@literal @PrimaryKey}
186: * long id;
187: *
188: * {@literal @SecondaryKey(relate=MANY_TO_ONE)}
189: * String department;
190: *
191: * String name;
192: *
193: * private Employee() {}
194: * }
195: *
196: * {@code SecondaryIndex<String,Long,Employee>} employeeByDepartment =
197: * store.getSecondaryIndex(primaryIndex, String.class, "department");</pre>
198: *
199: * <p>With a {@link Relationship#MANY_TO_ONE MANY_TO_ONE} relationship, the
200: * secondary key is not required to be unique; in other words, more than one
201: * entity may have the same secondary key value. In this example, more than
202: * one employee may belong to the same department.</p>
203: *
204: * <p>The most convenient way to access the employees in a given department is
205: * by using a sub-index. For example:</p>
206: *
207: * <pre class="code">
208: * {@code EntityIndex<Long,Entity>} subIndex = employeeByDepartment.subIndex(myDept);
209: * {@code EntityCursor<Employee>} cursor = subIndex.entities();
210: * try {
211: * for (Employee entity : cursor) {
212: * // Do something with the entity...
213: * }
214: * } finally {
215: * cursor.close();
216: * }</pre>
217: *
218: * <h3>One-to-Many Relationships</h3>
219: *
220: * <p>In a {@link Relationship#ONE_TO_MANY ONE_TO_MANY} relationship, a single
221: * entity is related to one or more secondary key values. For example:</p>
222: *
223: * <pre class="code">
224: * {@literal @Entity}
225: * class Employee {
226: *
227: * {@literal @PrimaryKey}
228: * long id;
229: *
230: * {@literal @SecondaryKey(relate=ONE_TO_MANY)}
231: * {@literal Set<String> emailAddresses = new HashSet<String>;}
232: *
233: * String name;
234: *
235: * private Employee() {}
236: * }
237: *
238: * {@code SecondaryIndex<String,Long,Employee>} employeeByEmail =
239: * store.getSecondaryIndex(primaryIndex, String.class, "emailAddresses");</pre>
240: *
241: * <p>With a {@link Relationship#ONE_TO_MANY ONE_TO_MANY} relationship, the
242: * secondary key must be unique; in other words, no two entities may have the
243: * same secondary key value. In this example, no two employees may have the
244: * same email address. If an attempt is made to store an entity having the
245: * same secondary key value as another existing entity, a {@link
246: * DatabaseException} will be thrown.</p>
247: *
248: * <p>Because the secondary key is unique, it is useful to lookup entities by
249: * secondary key using {@link EntityIndex#get}. For example:</p>
250: *
251: * <pre class="code">
252: * Employee employee = employeeByEmail.get(myEmailAddress);</pre>
253: *
254: * <p>The secondary key field for a {@link Relationship#ONE_TO_MANY
255: * ONE_TO_MANY} relationship must be an array or collection type. To access
256: * the email addresses of an employee, simply access the collection field
257: * directly. For example:</p>
258: *
259: * <pre class="code">
260: * Employee employee = primaryIndex.get(1); // Get the entity by primary key
261: * employee.emailAddresses.add(myNewEmail); // Add an email address
262: * primaryIndex.putNoReturn(1, employee); // Update the entity</pre>
263: *
264: * <h3>Many-to-Many Relationships</h3>
265: *
266: * <p>In a {@link Relationship#MANY_TO_MANY MANY_TO_MANY} relationship, one
267: * or more entities is related to one or more secondary key values. For
268: * example:</p>
269: *
270: * <pre class="code">
271: * {@literal @Entity}
272: * class Employee {
273: *
274: * {@literal @PrimaryKey}
275: * long id;
276: *
277: * {@literal @SecondaryKey(relate=MANY_TO_MANY)}
278: * {@literal Set<String> organizations = new HashSet<String>;}
279: *
280: * String name;
281: *
282: * private Employee() {}
283: * }
284: *
285: * {@code SecondaryIndex<String,Long,Employee>} employeeByOrganization =
286: * store.getSecondaryIndex(primaryIndex, String.class, "organizations");</pre>
287: *
288: * <p>With a {@link Relationship#MANY_TO_MANY MANY_TO_MANY} relationship, the
289: * secondary key is not required to be unique; in other words, more than one
290: * entity may have the same secondary key value. In this example, more than
291: * one employee may belong to the same organization.</p>
292: *
293: * <p>The most convenient way to access the employees in a given organization
294: * is by using a sub-index. For example:</p>
295: *
296: * <pre class="code">
297: * {@code EntityIndex<Long,Entity>} subIndex = employeeByOrganization.subIndex(myOrg);
298: * {@code EntityCursor<Employee>} cursor = subIndex.entities();
299: * try {
300: * for (Employee entity : cursor) {
301: * // Do something with the entity...
302: * }
303: * } finally {
304: * cursor.close();
305: * }</pre>
306: *
307: * <p>The secondary key field for a {@link Relationship#MANY_TO_MANY
308: * MANY_TO_MANY} relationship must be an array or collection type. To access
309: * the organizations of an employee, simply access the collection field
310: * directly. For example:</p>
311: *
312: * <pre class="code">
313: * Employee employee = primaryIndex.get(1); // Get the entity by primary key
314: * employee.organizations.remove(myOldOrg); // Remove an organization
315: * primaryIndex.putNoReturn(1, employee); // Update the entity</pre>
316: *
317: * <h3>Foreign Key Constraints for Related Entities</h3>
318: *
319: * <p>In all the examples above the secondary key is treated only as a simple
320: * value, such as a {@code String} department field. In many cases, that is
321: * sufficient. But in other cases, you may wish to constrain the secondary
322: * keys of one entity class to be valid primary keys of another entity
323: * class. For example, a Department entity may also be defined:</p>
324: *
325: * <pre class="code">
326: * {@literal @Entity}
327: * class Department {
328: *
329: * {@literal @PrimaryKey}
330: * String name;
331: *
332: * String missionStatement;
333: *
334: * private Department() {}
335: * }</pre>
336: *
337: * <p>You may wish to constrain the department field values of the Employee
338: * class in the examples above to be valid primary keys of the Department
339: * entity class. In other words, you may wish to ensure that the department
340: * field of an Employee will always refer to a valid Department entity.</p>
341: *
342: * <p>You can implement this constraint yourself by validating the department
343: * field before you store an Employee. For example:</p>
344: *
345: * <pre class="code">
346: * {@code PrimaryIndex<String,Department>} departmentIndex =
347: * store.getPrimaryIndex(String.class, Department.class);
348: *
349: * void storeEmployee(Employee employee) throws DatabaseException {
350: * if (departmentIndex.contains(employee.department)) {
351: * primaryIndex.putNoReturn(employee);
352: * } else {
353: * throw new IllegalArgumentException("Department does not exist: " +
354: * employee.department);
355: * }
356: * }</pre>
357: *
358: * <p>Or, instead you could define the Employee department field as a foreign
359: * key, and this validation will be done for you when you attempt to store the
360: * Employee entity. For example:</p>
361: *
362: * <pre class="code">
363: * {@literal @Entity}
364: * class Employee {
365: *
366: * {@literal @PrimaryKey}
367: * long id;
368: *
369: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class)}
370: * String department;
371: *
372: * String name;
373: *
374: * private Employee() {}
375: * }</pre>
376: *
377: * <p>The {@code relatedEntity=Department.class} above defines the department
378: * field as a foreign key that refers to a Department entity. Whenever a
379: * Employee entity is stored, its department field value will be checked to
380: * ensure that a Department entity exists with that value as its primary key.
381: * If no such Department entity exists, then a {@link DatabaseException} is
382: * thrown, causing the transaction to be aborted (assuming that transactions
383: * are used).</p>
384: *
385: * <p>This begs the question: What happens when a Department entity is deleted
386: * while one or more Employee entities have department fields that refer to
387: * the deleted department's primary key? If the department were allowed to be
388: * deleted, the foreign key constraint for the Employee department field would
389: * be violated, because the Employee department field would refer to a
390: * department that does not exist.</p>
391: *
392: * <p>By default, when this situation arises the system does not allow the
393: * department to be deleted. Instead, a {@link DatabaseException} is thrown,
394: * causing the transaction to be aborted. In this case, in order to delete a
395: * department, the department field of all Employee entities must first be
396: * updated to refer to a different existing department, or set to null. This
397: * is the responsibility of the application.</p>
398: *
399: * <p>There are two additional ways of handling deletion of a Department
400: * entity. These alternatives are configured using the {@link
401: * SecondaryKey#onRelatedEntityDelete} annotation property. Setting this
402: * property to {@link DeleteAction#NULLIFY} causes the Employee department
403: * field to be automatically set to null when the department they refer to is
404: * deleted. This may or may not be desirable, depending on application
405: * policies. For example:</p>
406: *
407: * <pre class="code">
408: * {@literal @Entity}
409: * class Employee {
410: *
411: * {@literal @PrimaryKey}
412: * long id;
413: *
414: * {@code @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class,
415: * onRelatedEntityDelete=NULLIFY)}
416: * String department;
417: *
418: * String name;
419: *
420: * private Employee() {}
421: * }</pre>
422: *
423: * <p>The {@link DeleteAction#CASCADE} value, on the other hand, causes the
424: * Employee entities to be automatically deleted when the department they refer
425: * to is deleted. This is probably not desirable in this particular example,
426: * but is useful for parent-child relationships. For example:</p>
427: *
428: * <pre class="code">
429: * {@literal @Entity}
430: * class Order {
431: *
432: * {@literal @PrimaryKey}
433: * long id;
434: *
435: * String description;
436: *
437: * private Order() {}
438: * }
439: *
440: * {@literal @Entity}
441: * class OrderItem {
442: *
443: * {@literal @PrimaryKey}
444: * long id;
445: *
446: * {@code @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Order.class,
447: * onRelatedEntityDelete=CASCADE)}
448: * long orderId;
449: *
450: * String description;
451: *
452: * private OrderItem() {}
453: * }</pre>
454: *
455: * <p>The OrderItem orderId field refers to its "parent" Order entity. When an
456: * Order entity is deleted, it may be useful to automatically delete its
457: * "child" OrderItem entities.</p>
458: *
459: * <p>For more information, see {@link SecondaryKey#onRelatedEntityDelete}.</p>
460: *
461: * <h3>One-to-Many versus Many-to-One for Related Entities</h3>
462: *
463: * <p>When there is a conceptual Many-to-One relationship such as Employee to
464: * Department as illustrated in the examples above, the relationship may be
465: * implemented either as Many-to-One in the Employee class or as One-to-Many in
466: * the Department class.</p>
467: *
468: * <p>Here is the Many-to-One approach.</p>
469: *
470: * <pre class="code">
471: * {@literal @Entity}
472: * class Employee {
473: *
474: * {@literal @PrimaryKey}
475: * long id;
476: *
477: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class)}
478: * String department;
479: *
480: * String name;
481: *
482: * private Employee() {}
483: * }
484: *
485: * {@literal @Entity}
486: * class Department {
487: *
488: * {@literal @PrimaryKey}
489: * String name;
490: *
491: * String missionStatement;
492: *
493: * private Department() {}
494: * }</pre>
495: *
496: * <p>And here is the One-to-Many approach.</p>
497: *
498: * <pre class="code">
499: * {@literal @Entity}
500: * class Employee {
501: *
502: * {@literal @PrimaryKey}
503: * long id;
504: *
505: * String name;
506: *
507: * private Employee() {}
508: * }
509: *
510: * {@literal @Entity}
511: * class Department {
512: *
513: * {@literal @PrimaryKey}
514: * String name;
515: *
516: * String missionStatement;
517: *
518: * {@literal @SecondaryKey(relate=ONE_TO_MANY, relatedEntity=Employee.class)}
519: * {@literal Set<Long> employees = new HashSet<Long>;}
520: *
521: * private Department() {}
522: * }</pre>
523: *
524: * <p>Which approach is best? The Many-to-One approach better handles large
525: * number of entities on the to-Many side of the relationship because it
526: * doesn't store a collection of keys as an entity field. With Many-to-One a
527: * Btree is used to store the collection of keys and the Btree can easily
528: * handle very large numbers of keys. With One-to-Many, each time a related
529: * key is added or removed the entity on the One side of the relationship,
530: * along with the complete collection of related keys, must be updated.
531: * Therefore, if large numbers of keys may be stored per relationship,
532: * Many-to-One is recommended.</p>
533: *
534: * <p>If the number of entities per relationship is not a concern, then you may
535: * wish to choose the approach that is most natural in your application data
536: * model. For example, if you think of a Department as containing employees
537: * and you wish to modify the Department object each time an employee is added
538: * or removed, then you may wish to store a collection of Employee keys in the
539: * Department object (One-to-Many).</p>
540: *
541: * <p>Note that if you have a One-to-Many relationship and there is no related
542: * entity, then you don't have a choice -- you have to use One-to-Many because
543: * there is no entity on the to-Many side of the relationship where a
544: * Many-to-One key could be defined. An example is the Employee to email
545: * addresses relationship discussed above:</p>
546: *
547: * <pre class="code">
548: * {@literal @Entity}
549: * class Employee {
550: *
551: * {@literal @PrimaryKey}
552: * long id;
553: *
554: * {@literal @SecondaryKey(relate=ONE_TO_MANY)}
555: * {@literal Set<String> emailAddresses = new HashSet<String>;}
556: *
557: * String name;
558: *
559: * private Employee() {}
560: * }</pre>
561: *
562: * <p>For sake of argument imagine that each employee has thousands of email
563: * addresses and employees frequently add and remove email addresses. To
564: * avoid the potential performance problems associated with updating the
565: * Employee entity every time an email address is added or removed, you could
566: * create an EmployeeEmailAddress entity and use a Many-to-One relationship as
567: * shown below:</p>
568: *
569: * <pre class="code">
570: * {@literal @Entity}
571: * class Employee {
572: *
573: * {@literal @PrimaryKey}
574: * long id;
575: *
576: * String name;
577: *
578: * private Employee() {}
579: * }
580: *
581: * {@literal @Entity}
582: * class EmployeeEmailAddress {
583: *
584: * {@literal @PrimaryKey}
585: * String emailAddress;
586: *
587: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Employee.class)}
588: * long employeeId;
589: *
590: * private EmployeeEmailAddress() {}
591: * }</pre>
592: *
593: * <h3>Key Placement with Many-to-Many for Related Entities</h3>
594: *
595: * <p>As discussed in the section above, one drawback of a to-Many relationship
596: * (One-to-Many was discussed above and Many-to-Many is discussed here) is that
597: * it requires storing a collection of keys in an entity. Each time a key is
598: * added or removed, the containing entity must be updated. This has potential
599: * performance problems when there are large numbers of entities on the to-Many
600: * side of the relationship, in other words, when there are large numbers of
601: * keys in each secondary key field collection.</p>
602: *
603: * <p>If you have a Many-to-Many relationship with a reasonably small number of
604: * entities on one side of the relationship and a large number of entities on
605: * the other side, you can avoid the potential performance problems by defining
606: * the secondary key field on the side with a small number of entities.</p>
607: *
608: * <p>For example, in an Employee-to-Organization relationship, the number of
609: * organizations per employee will normally be reasonably small but the number
610: * of employees per organization may be very large. Therefore, to avoid
611: * potential performance problems, the secondary key field should be defined in
612: * the Employee class as shown below.</p>
613: *
614: * <pre class="code">
615: * {@literal @Entity}
616: * class Employee {
617: *
618: * {@literal @PrimaryKey}
619: * long id;
620: *
621: * {@literal @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Organization.class)}
622: * {@literal Set<String> organizations = new HashSet<String>;}
623: *
624: * String name;
625: *
626: * private Employee() {}
627: * }
628: *
629: * {@literal @Entity}
630: * class Organization {
631: *
632: * {@literal @PrimaryKey}
633: * String name;
634: *
635: * String description;
636: * }</pre>
637: *
638: * <p>If instead a {@code Set<Long> members} key had been defined in the
639: * Organization class, this set could potentially have a large number of
640: * elements and performance problems could result.</p>
641: *
642: * <h3>Many-to-Many Versus a Relationship Entity</h3>
643: *
644: * <p>If you have a Many-to-Many relationship with a large number of entities
645: * on <em>both</em> sides of the relationship, you can avoid the potential
646: * performance problems by using a <em>relationship entity</em>. A
647: * relationship entity defines the relationship between two other entities
648: * using two Many-to-One relationships.</p>
649: *
650: * <p>Imagine a relationship between cars and trucks indicating whenever a
651: * particular truck was passed on the road by a particular car. A given car
652: * may pass a large number of trucks and a given truck may be passed by a large
653: * number of cars. First look at a Many-to-Many relationship between these two
654: * entities:</p>
655: *
656: * <pre class="code">
657: * {@literal @Entity}
658: * class Car {
659: *
660: * {@literal @PrimaryKey}
661: * String licenseNumber;
662: *
663: * {@literal @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Truck.class)}
664: * {@literal Set<String> trucksPassed = new HashSet<String>;}
665: *
666: * String color;
667: *
668: * private Car() {}
669: * }
670: *
671: * {@literal @Entity}
672: * class Truck {
673: *
674: * {@literal @PrimaryKey}
675: * String licenseNumber;
676: *
677: * int tons;
678: *
679: * private Truck() {}
680: * }</pre>
681: *
682: * <p>With the Many-to-Many approach above, the {@code trucksPassed} set could
683: * potentially have a large number of elements and performance problems could
684: * result.</p>
685: *
686: * <p>To apply the relationship entity approach we define a new entity class
687: * named CarPassedTruck representing a single truck passed by a single car. We
688: * remove the secondary key from the Car class and use two secondary keys in
689: * the CarPassedTruck class instead.</p>
690: *
691: * <pre class="code">
692: * {@literal @Entity}
693: * class Car {
694: *
695: * {@literal @PrimaryKey}
696: * String licenseNumber;
697: *
698: * String color;
699: *
700: * private Car() {}
701: * }
702: *
703: * {@literal @Entity}
704: * class Truck {
705: *
706: * {@literal @PrimaryKey}
707: * String licenseNumber;
708: *
709: * int tons;
710: *
711: * private Truck() {}
712: * }
713: *
714: * {@literal @Entity}
715: * class CarPassedTruck {
716: *
717: * {@literal @PrimaryKey}
718: * long id;
719: *
720: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Car.class)}
721: * String carLicense;
722: *
723: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Truck.class)}
724: * String truckLicense;
725: *
726: * private CarPassedTruck() {}
727: * }</pre>
728: *
729: * <p>The CarPassedTruck entity can be used to access the relationship by car
730: * license or by truck license.</p>
731: *
732: * <p>You may use the relationship entity approach because of the potential
733: * performance problems mentioned above. Or, you may choose to use this
734: * approach in order to store other information about the relationship. For
735: * example, if for each car that passes a truck you wish to record how much
736: * faster the car was going than the truck, then a relationship entity is the
737: * logical place to store that property. In the example below the
738: * speedDifference property is added to the CarPassedTruck class.</p>
739: *
740: * <pre class="code">
741: * {@literal @Entity}
742: * class CarPassedTruck {
743: *
744: * {@literal @PrimaryKey}
745: * long id;
746: *
747: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Car.class)}
748: * String carLicense;
749: *
750: * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Truck.class)}
751: * String truckLicense;
752: *
753: * int speedDifference;
754: *
755: * private CarPassedTruck() {}
756: * }</pre>
757: *
758: * <p>Be aware that the relationship entity approach adds overhead compared to
759: * Many-to-Many. There is one additional entity and one additional secondary
760: * key. These factors should be weighed against its advantages and the
761: * relevant application access patterns should be considered.</p>
762: *
763: * @author Mark Hayes
764: */
765: public class SecondaryIndex<SK, PK, E> extends BasicIndex<SK, E> {
766:
767: private SecondaryDatabase secDb;
768: private Database keysDb;
769: private PrimaryIndex priIndex;
770: private EntityBinding entityBinding;
771: private EntityIndex<SK, PK> keysIndex;
772: private SortedMap<SK, E> map;
773:
774: /**
775: * Creates a secondary index without using an <code>EntityStore</code>.
776: * When using an {@link EntityStore}, call {@link
777: * EntityStore#getSecondaryIndex getSecondaryIndex} instead.
778: *
779: * <p>This constructor is not normally needed and is provided for
780: * applications that wish to use custom bindings along with the Direct
781: * Persistence Layer. Normally, {@link EntityStore#getSecondaryIndex
782: * getSecondaryIndex} is used instead.</p>
783: *
784: * @param database the secondary database used for all access other than
785: * via a {@link #keysIndex}.
786: *
787: * @param keysDatabase another handle on the secondary database, opened
788: * without association to the primary, and used only for access via a
789: * {@link #keysIndex}. If this argument is null and the {@link #keysIndex}
790: * method is called, then the keys database will be opened automatically;
791: * however, the user is then responsible for closing the keys database. To
792: * get the keys database in order to close it, call {@link
793: * #getKeysDatabase}.
794: *
795: * @param primaryIndex the primary index associated with this secondary
796: * index.
797: *
798: * @param secondaryKeyClass the class of the secondary key.
799: *
800: * @param secondaryKeyBinding the binding to be used for secondary keys.
801: */
802: public SecondaryIndex(SecondaryDatabase database,
803: Database keysDatabase, PrimaryIndex<PK, E> primaryIndex,
804: Class<SK> secondaryKeyClass,
805: EntryBinding secondaryKeyBinding) throws DatabaseException {
806:
807: super (database, secondaryKeyClass, secondaryKeyBinding,
808: new EntityValueAdapter(primaryIndex.getEntityClass(),
809: primaryIndex.getEntityBinding(), true));
810: secDb = database;
811: keysDb = keysDatabase;
812: priIndex = primaryIndex;
813: entityBinding = primaryIndex.getEntityBinding();
814: }
815:
816: /**
817: * Returns the underlying secondary database for this index.
818: *
819: * @return the secondary database.
820: */
821: public SecondaryDatabase getDatabase() {
822: return secDb;
823: }
824:
825: /**
826: * Returns the underlying secondary database that is not associated with
827: * the primary database and is used for the {@link #keysIndex}.
828: *
829: * @return the keys database.
830: */
831: public Database getKeysDatabase() {
832: return keysDb;
833: }
834:
835: /**
836: * Returns the primary index associated with this secondary index.
837: *
838: * @return the primary index.
839: */
840: public PrimaryIndex<PK, E> getPrimaryIndex() {
841: return priIndex;
842: }
843:
844: /**
845: * Returns the secondary key class for this index.
846: *
847: * @return the class.
848: */
849: public Class<SK> getKeyClass() {
850: return keyClass;
851: }
852:
853: /**
854: * Returns the secondary key binding for the index.
855: *
856: * @return the key binding.
857: */
858: public EntryBinding getKeyBinding() {
859: return keyBinding;
860: }
861:
862: /**
863: * Returns a read-only keys index that maps secondary key to primary key.
864: * When accessing the keys index, the primary key is returned rather than
865: * the entity. When only the primary key is needed and not the entire
866: * entity, using the keys index is less expensive than using the secondary
867: * index because the primary index does not have to be accessed.
868: *
869: * <p>Note the following in the unusual case that you are <em>not</em>
870: * using an <code>EntityStore</code>: This method will open the keys
871: * database, a second database handle for the secondary database, if it is
872: * not already open. In this case, if you are <em>not</em> using an
873: * <code>EntityStore</code>, then you are responsible for closing the
874: * database returned by {@link #getKeysDatabase} before closing the
875: * environment. If you <em>are</em> using an <code>EntityStore</code>, the
876: * keys database will be closed automatically by {@link
877: * EntityStore#close}.</p>
878: *
879: * @return the keys index.
880: */
881: public synchronized EntityIndex<SK, PK> keysIndex()
882: throws DatabaseException {
883:
884: if (keysIndex == null) {
885: if (keysDb == null) {
886: DatabaseConfig config = secDb.getConfig();
887: config.setReadOnly(true);
888: keysDb = db.getEnvironment().openDatabase(null,
889: secDb.getDatabaseName(), config);
890: }
891: keysIndex = new KeysIndex<SK, PK>(keysDb, keyClass,
892: keyBinding, priIndex.getKeyClass(), priIndex
893: .getKeyBinding());
894: }
895: return keysIndex;
896: }
897:
898: /**
899: * Returns an index that maps primary key to entity for the subset of
900: * entities having a given secondary key (duplicates). A sub-index is
901: * convenient when you are interested in working with the subset of
902: * entities having a particular secondary key value.
903: *
904: * <p>When using a {@link Relationship#MANY_TO_ONE MANY_TO_ONE} or {@link
905: * Relationship#MANY_TO_MANY MANY_TO_MANY} secondary key, the sub-index
906: * represents the left (MANY) side of a relationship.</p>
907: *
908: * @param key the secondary key that identifies the entities in the
909: * sub-index.
910: *
911: * @return the sub-index.
912: */
913: public EntityIndex<PK, E> subIndex(SK key) throws DatabaseException {
914:
915: return new SubIndex(this , entityBinding, key);
916: }
917:
918: /*
919: * Of the EntityIndex methods only get()/map()/sortedMap() are implemented
920: * here. All other methods are implemented by BasicIndex.
921: */
922:
923: public E get(SK key) throws DatabaseException {
924:
925: return get(null, key, null);
926: }
927:
928: public E get(Transaction txn, SK key, LockMode lockMode)
929: throws DatabaseException {
930:
931: DatabaseEntry keyEntry = new DatabaseEntry();
932: DatabaseEntry pkeyEntry = new DatabaseEntry();
933: DatabaseEntry dataEntry = new DatabaseEntry();
934: keyBinding.objectToEntry(key, keyEntry);
935:
936: OperationStatus status = secDb.get(txn, keyEntry, pkeyEntry,
937: dataEntry, lockMode);
938:
939: if (status == OperationStatus.SUCCESS) {
940: return (E) entityBinding
941: .entryToObject(pkeyEntry, dataEntry);
942: } else {
943: return null;
944: }
945: }
946:
947: public Map<SK, E> map() {
948: return sortedMap();
949: }
950:
951: public synchronized SortedMap<SK, E> sortedMap() {
952: if (map == null) {
953: map = new StoredSortedMap(db, keyBinding, entityBinding,
954: true);
955: }
956: return map;
957: }
958: }
|