001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: EntityCursor.java,v 1.9.2.3 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.persist;
010:
011: import java.util.Iterator;
012:
013: import com.sleepycat.je.CursorConfig;
014: import com.sleepycat.je.DatabaseException;
015: import com.sleepycat.je.LockMode;
016: import com.sleepycat.je.Transaction;
017: import com.sleepycat.persist.model.Relationship;
018: import com.sleepycat.persist.model.SecondaryKey;
019:
020: /**
021: * Traverses entity values or key values and allows deleting or updating the
022: * entity at the current cursor position. The value type (V) is either an
023: * entity class or a key class, depending on how the cursor was opened.
024: *
025: * <p>{@code EntityCursor} objects are <em>not</em> thread-safe. Cursors
026: * should be opened, used and closed by a single thread.</p>
027: *
028: * <p>Cursors are opened using the {@link EntityIndex#keys} and {@link
029: * EntityIndex#entities} family of methods. These methods are available for
030: * objects of any class that implements {@link EntityIndex}: {@link
031: * PrimaryIndex}, {@link SecondaryIndex}, and the indices returned by {@link
032: * SecondaryIndex#keysIndex} and {@link SecondaryIndex#subIndex}. A {@link
033: * ForwardCursor}, which implements a subset of cursor operations, is also
034: * available via the {@link EntityJoin#keys} and {@link EntityJoin#entities}
035: * methods.</p>
036: *
037: * <p>Values are always returned by a cursor in key order, where the key is
038: * defined by the underlying {@link EntityIndex}. For example, a cursor on a
039: * {@link SecondaryIndex} returns values ordered by secondary key, while an
040: * index on a {@link PrimaryIndex} or a {@link SecondaryIndex#subIndex} returns
041: * values ordered by primary key.</p>
042: *
043: * <p><em>WARNING:</em> Cursors must always be closed to prevent resource leaks
044: * which could lead to the index becoming unusable or cause an
045: * <code>OutOfMemoryError</code>. To ensure that a cursor is closed in the
046: * face of exceptions, call {@link #close} in a finally block. For example,
047: * the following code traverses all Employee entities and closes the cursor
048: * whether or not an exception occurs:</p>
049: *
050: * <pre class="code">
051: * {@literal @Entity}
052: * class Employee {
053: *
054: * {@literal @PrimaryKey}
055: * long id;
056: *
057: * {@literal @SecondaryKey(relate=MANY_TO_ONE)}
058: * String department;
059: *
060: * String name;
061: *
062: * private Employee() {}
063: * }
064: *
065: * EntityStore store = ...
066: *
067: * {@code PrimaryIndex<Long,Employee>} primaryIndex =
068: * store.getPrimaryIndex(Long.class, Employee.class);
069: *
070: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
071: * try {
072: * for (Employee entity = cursor.first();
073: * entity != null;
074: * entity = cursor.next()) {
075: * // Do something with the entity...
076: * }
077: * } finally {
078: * cursor.close();
079: * }</pre>
080: *
081: * <h3>Initializing the Cursor Position</h3>
082: *
083: * <p>When it is opened, a cursor is not initially positioned on any value; in
084: * other words, it is uninitialized. Most methods in this interface initialize
085: * the cursor position but certain methods, for example, {@link #current} and
086: * {@link #delete}, throw {@link IllegalStateException} when called for an
087: * uninitialized cursor.</p>
088: *
089: * <p>Note that the {@link #next} and {@link #prev} methods return the first or
090: * last value respectively for an uninitialized cursor. This allows the loop
091: * in the example above to be rewritten as follows:</p>
092: *
093: * <pre class="code">
094: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
095: * try {
096: * Employee entity;
097: * while ((entity = cursor.next()) != null) {
098: * // Do something with the entity...
099: * }
100: * } finally {
101: * cursor.close();
102: * }</pre>
103: *
104: * <h3>Cursors and Iterators</h3>
105: *
106: * <p>The {@link #iterator} method can be used to return a standard Java {@code
107: * Iterator} that returns the same values that the cursor returns. For
108: * example:</p>
109: *
110: * <pre class="code">
111: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
112: * try {
113: * {@code Iterator<Employee>} i = cursor.iterator();
114: * while (i.hasNext()) {
115: * Employee entity = i.next();
116: * // Do something with the entity...
117: * }
118: * } finally {
119: * cursor.close();
120: * }</pre>
121: *
122: * <p>The {@link Iterable} interface is also extended by {@link EntityCursor}
123: * to allow using the cursor as the target of a Java "foreach" statement:</p>
124: *
125: * <pre class="code">
126: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
127: * try {
128: * for (Employee entity : cursor) {
129: * // Do something with the entity...
130: * }
131: * } finally {
132: * cursor.close();
133: * }</pre>
134: *
135: * <p>The iterator uses the cursor directly, so any changes to the cursor
136: * position impact the iterator and vice versa. The iterator advances the
137: * cursor by calling {@link #next()} when {@link Iterator#hasNext} or {@link
138: * Iterator#next} is called. Because of this interaction, to keep things
139: * simple it is best not to mix the use of an {@code EntityCursor}
140: * {@code Iterator} with the use of the {@code EntityCursor} traversal methods
141: * such as {@link #next()}, for a single {@code EntityCursor} object.</p>
142: *
143: * <h3>Key Ranges</h3>
144: *
145: * <p>A key range may be specified when opening the cursor, to restrict the
146: * key range of the cursor to a subset of the complete range of keys in the
147: * index. A {@code fromKey} and/or {@code toKey} parameter may be specified
148: * when calling {@link EntityIndex#keys(Object,boolean,Object,boolean)} or
149: * {@link EntityIndex#entities(Object,boolean,Object,boolean)}. The key
150: * arguments may be specified as inclusive or exclusive values.</p>
151: *
152: * <p>Whenever a cursor with a key range is moved, the key range bounds will be
153: * checked, and the cursor will never be positioned outside the range. The
154: * {@link #first} cursor value is the first existing value in the range, and
155: * the {@link #last} cursor value is the last existing value in the range. For
156: * example, the following code traverses Employee entities with keys from 100
157: * (inclusive) to 200 (exclusive):</p>
158: *
159: * <pre class="code">
160: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities(100, true, 200, false);
161: * try {
162: * for (Employee entity : cursor) {
163: * // Do something with the entity...
164: * }
165: * } finally {
166: * cursor.close();
167: * }</pre>
168: *
169: * <h3>Duplicate Keys</h3>
170: *
171: * <p>When using a cursor for a {@link SecondaryIndex}, the keys in the index
172: * may be non-unique (duplicates) if {@link SecondaryKey#relate} is {@link
173: * Relationship#MANY_TO_ONE MANY_TO_ONE} or {@link Relationship#MANY_TO_MANY
174: * MANY_TO_MANY}. For example, a {@code MANY_TO_ONE} {@code
175: * Employee.department} secondary key is non-unique because there are multiple
176: * Employee entities with the same department key value. The {@link #nextDup},
177: * {@link #prevDup}, {@link #nextNoDup} and {@link #prevNoDup} methods may be
178: * used to control how non-unique keys are returned by the cursor.</p>
179: *
180: * <p>{@link #nextDup} and {@link #prevDup} return the next or previous value
181: * only if it has the same key as the current value, and null is returned when
182: * a different key is encountered. For example, these methods can be used to
183: * return all employees in a given department.</p>
184: *
185: * <p>{@link #nextNoDup} and {@link #prevNoDup} return the next or previous
186: * value with a unique key, skipping over values that have the same key. For
187: * example, these methods can be used to return the first employee in each
188: * department.</p>
189: *
190: * <p>For example, the following code will find the first employee in each
191: * department with {@link #nextNoDup} until it finds a department name that
192: * matches a particular regular expression. For each matching department it
193: * will find all employees in that department using {@link #nextDup}.</p>
194: *
195: * <pre class="code">
196: * {@code SecondaryIndex<String,Long,Employee>} secondaryIndex =
197: * store.getSecondaryIndex(primaryIndex, String.class, "department");
198: *
199: * String regex = ...;
200: * {@code EntityCursor<Employee>} cursor = secondaryIndex.entities();
201: * try {
202: * for (Employee entity = cursor.first();
203: * entity != null;
204: * entity = cursor.nextNoDup()) {
205: * if (entity.department.matches(regex)) {
206: * while (entity != null) {
207: * // Do something with the matching entities...
208: * entity = cursor.nextDup();
209: * }
210: * }
211: * }
212: * } finally {
213: * cursor.close();
214: * }</pre>
215: *
216: * <h3>Updating and Deleting Entities with a Cursor</h3>
217: *
218: * <p>The {@link #update} and {@link #delete} methods operate on the entity at
219: * the current cursor position. Cursors on any type of index may be used to
220: * delete entities. For example, the following code deletes all employees in
221: * departments which have names that match a particular regular expression:</p>
222: *
223: * <pre class="code">
224: * {@code SecondaryIndex<String,Long,Employee>} secondaryIndex =
225: * store.getSecondaryIndex(primaryIndex, String.class, "department");
226: *
227: * String regex = ...;
228: * {@code EntityCursor<Employee>} cursor = secondaryIndex.entities();
229: * try {
230: * for (Employee entity = cursor.first();
231: * entity != null;
232: * entity = cursor.nextNoDup()) {
233: * if (entity.department.matches(regex)) {
234: * while (entity != null) {
235: * cursor.delete();
236: * entity = cursor.nextDup();
237: * }
238: * }
239: * }
240: * } finally {
241: * cursor.close();
242: * }</pre>
243: *
244: * <p>Note that the cursor can be moved to the next (or previous) value after
245: * deleting the entity at the current position. This is an important property
246: * of cursors, since without it you would not be able to easily delete while
247: * processing multiple values with a cursor. A cursor positioned on a deleted
248: * entity is in a special state. In this state, {@link #current} will return
249: * null, {@link #delete} will return false, and {@link #update} will return
250: * false.</p>
251: *
252: * <p>The {@link #update} method is supported only if the value type is an
253: * entity class (not a key class) and the underlying index is a {@link
254: * PrimaryIndex}; in other words, for a cursor returned by one of the {@link
255: * PrimaryIndex#entities} methods. For example, the following code changes all
256: * employee names to uppercase:</p>
257: *
258: * <pre class="code">
259: * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
260: * try {
261: * for (Employee entity = cursor.first();
262: * entity != null;
263: * entity = cursor.next()) {
264: * entity.name = entity.name.toUpperCase();
265: * cursor.update(entity);
266: * }
267: * } finally {
268: * cursor.close();
269: * }</pre>
270: *
271: * @author Mark Hayes
272: */
273: public interface EntityCursor<V> extends ForwardCursor<V> {
274:
275: /**
276: * Moves the cursor to the first value and returns it, or returns null if
277: * the cursor range is empty.
278: *
279: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
280: *
281: * @return the first value, or null if the cursor range is empty.
282: */
283: V first() throws DatabaseException;
284:
285: /**
286: * Moves the cursor to the first value and returns it, or returns null if
287: * the cursor range is empty.
288: *
289: * @param lockMode the lock mode to use for this operation, or null to
290: * use {@link LockMode#DEFAULT}.
291: *
292: * @return the first value, or null if the cursor range is empty.
293: */
294: V first(LockMode lockMode) throws DatabaseException;
295:
296: /**
297: * Moves the cursor to the last value and returns it, or returns null if
298: * the cursor range is empty.
299: *
300: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
301: *
302: * @return the last value, or null if the cursor range is empty.
303: */
304: V last() throws DatabaseException;
305:
306: /**
307: * Moves the cursor to the last value and returns it, or returns null if
308: * the cursor range is empty.
309: *
310: * @param lockMode the lock mode to use for this operation, or null to
311: * use {@link LockMode#DEFAULT}.
312: *
313: * @return the last value, or null if the cursor range is empty.
314: */
315: V last(LockMode lockMode) throws DatabaseException;
316:
317: /**
318: * Moves the cursor to the next value and returns it, or returns null
319: * if there are no more values in the cursor range. If the cursor is
320: * uninitialized, this method is equivalent to {@link #first}.
321: *
322: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
323: *
324: * @return the next value, or null if there are no more values in the
325: * cursor range.
326: */
327: V next() throws DatabaseException;
328:
329: /**
330: * Moves the cursor to the next value and returns it, or returns null
331: * if there are no more values in the cursor range. If the cursor is
332: * uninitialized, this method is equivalent to {@link #first}.
333: *
334: * @param lockMode the lock mode to use for this operation, or null to
335: * use {@link LockMode#DEFAULT}.
336: *
337: * @return the next value, or null if there are no more values in the
338: * cursor range.
339: */
340: V next(LockMode lockMode) throws DatabaseException;
341:
342: /**
343: * Moves the cursor to the next value with the same key (duplicate) and
344: * returns it, or returns null if no more values are present for the key at
345: * the current position.
346: *
347: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
348: *
349: * @return the next value with the same key, or null if no more values are
350: * present for the key at the current position.
351: *
352: * @throws IllegalStateException if the cursor is uninitialized.
353: */
354: V nextDup() throws DatabaseException;
355:
356: /**
357: * Moves the cursor to the next value with the same key (duplicate) and
358: * returns it, or returns null if no more values are present for the key at
359: * the current position.
360: *
361: * @param lockMode the lock mode to use for this operation, or null to
362: * use {@link LockMode#DEFAULT}.
363: *
364: * @return the next value with the same key, or null if no more values are
365: * present for the key at the current position.
366: *
367: * @throws IllegalStateException if the cursor is uninitialized.
368: */
369: V nextDup(LockMode lockMode) throws DatabaseException;
370:
371: /**
372: * Moves the cursor to the next value with a different key and returns it,
373: * or returns null if there are no more unique keys in the cursor range.
374: * If the cursor is uninitialized, this method is equivalent to {@link
375: * #first}.
376: *
377: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
378: *
379: * @return the next value with a different key, or null if there are no
380: * more unique keys in the cursor range.
381: */
382: V nextNoDup() throws DatabaseException;
383:
384: /**
385: * Moves the cursor to the next value with a different key and returns it,
386: * or returns null if there are no more unique keys in the cursor range.
387: * If the cursor is uninitialized, this method is equivalent to {@link
388: * #first}.
389: *
390: * @param lockMode the lock mode to use for this operation, or null to
391: * use {@link LockMode#DEFAULT}.
392: *
393: * @return the next value with a different key, or null if there are no
394: * more unique keys in the cursor range.
395: */
396: V nextNoDup(LockMode lockMode) throws DatabaseException;
397:
398: /**
399: * Moves the cursor to the previous value and returns it, or returns null
400: * if there are no preceding values in the cursor range. If the cursor is
401: * uninitialized, this method is equivalent to {@link #last}.
402: *
403: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
404: *
405: * @return the previous value, or null if there are no preceding values in
406: * the cursor range.
407: */
408: V prev() throws DatabaseException;
409:
410: /**
411: * Moves the cursor to the previous value and returns it, or returns null
412: * if there are no preceding values in the cursor range. If the cursor is
413: * uninitialized, this method is equivalent to {@link #last}.
414: *
415: * @param lockMode the lock mode to use for this operation, or null to
416: * use {@link LockMode#DEFAULT}.
417: *
418: * @return the previous value, or null if there are no preceding values in
419: * the cursor range.
420: */
421: V prev(LockMode lockMode) throws DatabaseException;
422:
423: /**
424: * Moves the cursor to the previous value with the same key (duplicate) and
425: * returns it, or returns null if no preceding values are present for the
426: * key at the current position.
427: *
428: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
429: *
430: * @return the previous value with the same key, or null if no preceding
431: * values are present for the key at the current position.
432: *
433: * @throws IllegalStateException if the cursor is uninitialized.
434: */
435: V prevDup() throws DatabaseException;
436:
437: /**
438: * Moves the cursor to the previous value with the same key (duplicate) and
439: * returns it, or returns null if no preceding values are present for the
440: * key at the current position.
441: *
442: * @param lockMode the lock mode to use for this operation, or null to
443: * use {@link LockMode#DEFAULT}.
444: *
445: * @return the previous value with the same key, or null if no preceding
446: * values are present for the key at the current position.
447: *
448: * @throws IllegalStateException if the cursor is uninitialized.
449: */
450: V prevDup(LockMode lockMode) throws DatabaseException;
451:
452: /**
453: * Moves the cursor to the preceding value with a different key and returns
454: * it, or returns null if there are no preceding unique keys in the cursor
455: * range. If the cursor is uninitialized, this method is equivalent to
456: * {@link #last}.
457: *
458: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
459: *
460: * @return the previous value with a different key, or null if there are no
461: * preceding unique keys in the cursor range.
462: */
463: V prevNoDup() throws DatabaseException;
464:
465: /**
466: * Moves the cursor to the preceding value with a different key and returns
467: * it, or returns null if there are no preceding unique keys in the cursor
468: * range. If the cursor is uninitialized, this method is equivalent to
469: * {@link #last}.
470: *
471: * @param lockMode the lock mode to use for this operation, or null to
472: * use {@link LockMode#DEFAULT}.
473: *
474: * @return the previous value with a different key, or null if there are no
475: * preceding unique keys in the cursor range.
476: */
477: V prevNoDup(LockMode lockMode) throws DatabaseException;
478:
479: /**
480: * Returns the value at the cursor position, or null if the value at the
481: * cursor position has been deleted.
482: *
483: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
484: *
485: * @return the value at the cursor position, or null if it has been
486: * deleted.
487: *
488: * @throws IllegalStateException if the cursor is uninitialized.
489: */
490: V current() throws DatabaseException;
491:
492: /**
493: * Returns the value at the cursor position, or null if the value at the
494: * cursor position has been deleted.
495: *
496: * @param lockMode the lock mode to use for this operation, or null to
497: * use {@link LockMode#DEFAULT}.
498: *
499: * @return the value at the cursor position, or null if it has been
500: * deleted.
501: *
502: * @throws IllegalStateException if the cursor is uninitialized.
503: */
504: V current(LockMode lockMode) throws DatabaseException;
505:
506: /**
507: * Returns the number of values (duplicates) for the key at the cursor
508: * position, or returns zero if all values for the key have been deleted,
509: * Returns one or zero if the underlying index has unique keys.
510: *
511: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
512: *
513: * @return the number of duplicates, or zero if all values for the current
514: * key have been deleted.
515: *
516: * @throws IllegalStateException if the cursor is uninitialized.
517: */
518: int count() throws DatabaseException;
519:
520: /**
521: * Returns an iterator over the key range, starting with the value
522: * following the current position or at the first value if the cursor is
523: * uninitialized.
524: *
525: * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
526: *
527: * @return the iterator.
528: */
529: Iterator<V> iterator();
530:
531: /**
532: * Returns an iterator over the key range, starting with the value
533: * following the current position or at the first value if the cursor is
534: * uninitialized.
535: *
536: * @param lockMode the lock mode to use for all operations performed
537: * using the iterator, or null to use {@link LockMode#DEFAULT}.
538: *
539: * @return the iterator.
540: */
541: Iterator<V> iterator(LockMode lockMode);
542:
543: /**
544: * Replaces the entity at the cursor position with the given entity.
545: *
546: * @param entity the entity to replace the entity at the current position.
547: *
548: * @return true if successful or false if the entity at the current
549: * position was previously deleted.
550: *
551: * @throws IllegalStateException if the cursor is uninitialized.
552: *
553: * @throws UnsupportedOperationException if the index is read only or if
554: * the value type is not an entity type.
555: */
556: boolean update(V entity) throws DatabaseException;
557:
558: /**
559: * Deletes the entity at the cursor position.
560: *
561: * @throws IllegalStateException if the cursor is uninitialized.
562: *
563: * @throws UnsupportedOperationException if the index is read only.
564: *
565: * @return true if successful or false if the entity at the current
566: * position has been deleted.
567: */
568: boolean delete() throws DatabaseException;
569:
570: /**
571: * Duplicates the cursor at the cursor position. The returned cursor will
572: * be initially positioned at the same position as this current cursor, and
573: * will inherit this cursor's {@link Transaction} and {@link CursorConfig}.
574: *
575: * @return the duplicated cursor.
576: */
577: EntityCursor<V> dup() throws DatabaseException;
578:
579: /**
580: * Closes the cursor.
581: */
582: void close() throws DatabaseException;
583: }
|