1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: EntityCursor.java,v 1.1 2008/02/07 17:12:26 mark Exp $
7 */
8
9package com.sleepycat.persist;
10
11import java.util.Iterator;
12
13import com.sleepycat.db.CursorConfig;
14import com.sleepycat.db.DatabaseException;
15import com.sleepycat.db.LockMode;
16import com.sleepycat.db.Transaction;
17import com.sleepycat.persist.model.Relationship;
18import com.sleepycat.persist.model.SecondaryKey;
19
20/**
21 * Traverses entity values or key values and allows deleting or updating the
22 * entity at the current cursor position.  The value type (V) is either an
23 * entity class or a key class, depending on how the cursor was opened.
24 *
25 * <p>{@code EntityCursor} objects are <em>not</em> thread-safe.  Cursors
26 * should be opened, used and closed by a single thread.</p>
27 *
28 * <p>Cursors are opened using the {@link EntityIndex#keys} and {@link
29 * EntityIndex#entities} family of methods.  These methods are available for
30 * objects of any class that implements {@link EntityIndex}: {@link
31 * PrimaryIndex}, {@link SecondaryIndex}, and the indices returned by {@link
32 * SecondaryIndex#keysIndex} and {@link SecondaryIndex#subIndex}.  A {@link
33 * ForwardCursor}, which implements a subset of cursor operations, is also
34 * available via the {@link EntityJoin#keys} and {@link EntityJoin#entities}
35 * methods.</p>
36 *
37 * <p>Values are always returned by a cursor in key order, where the key is
38 * defined by the underlying {@link EntityIndex}.  For example, a cursor on a
39 * {@link SecondaryIndex} returns values ordered by secondary key, while an
40 * index on a {@link PrimaryIndex} or a {@link SecondaryIndex#subIndex} returns
41 * values ordered by primary key.</p>
42 *
43 * <p><em>WARNING:</em> Cursors must always be closed to prevent resource leaks
44 * which could lead to the index becoming unusable or cause an
45 * <code>OutOfMemoryError</code>.  To ensure that a cursor is closed in the
46 * face of exceptions, call {@link #close} in a finally block.  For example,
47 * the following code traverses all Employee entities and closes the cursor
48 * whether or not an exception occurs:</p>
49 *
50 * <pre class="code">
51 * {@literal @Entity}
52 * class Employee {
53 *
54 *     {@literal @PrimaryKey}
55 *     long id;
56 *
57 *     {@literal @SecondaryKey(relate=MANY_TO_ONE)}
58 *     String department;
59 *
60 *     String name;
61 *
62 *     private Employee() {}
63 * }
64 *
65 * EntityStore store = ...
66 *
67 * {@code PrimaryIndex<Long,Employee>} primaryIndex =
68 *     store.getPrimaryIndex(Long.class, Employee.class);
69 *
70 * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
71 * try {
72 *     for (Employee entity = cursor.first();
73 *                   entity != null;
74 *                   entity = cursor.next()) {
75 *         // Do something with the entity...
76 *     }
77 * } finally {
78 *     cursor.close();
79 * }</pre>
80 *
81 * <h3>Initializing the Cursor Position</h3>
82 *
83 * <p>When it is opened, a cursor is not initially positioned on any value; in
84 * other words, it is uninitialized.  Most methods in this interface initialize
85 * the cursor position but certain methods, for example, {@link #current} and
86 * {@link #delete}, throw {@link IllegalStateException} when called for an
87 * uninitialized cursor.</p>
88 *
89 * <p>Note that the {@link #next} and {@link #prev} methods return the first or
90 * last value respectively for an uninitialized cursor.  This allows the loop
91 * in the example above to be rewritten as follows:</p>
92 *
93 * <pre class="code">
94 * {@code EntityCursor<Employee>} cursor = primaryIndex.entities();
95 * try {
96 *     Employee entity;
97 *     while ((entity = cursor.next()) != null) {
98 *         // Do something with the entity...
99 *     }
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 */
273public 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()
284        throws DatabaseException;
285
286    /**
287     * Moves the cursor to the first value and returns it, or returns null if
288     * the cursor range is empty.
289     *
290     * @param lockMode the lock mode to use for this operation, or null to
291     * use {@link LockMode#DEFAULT}.
292     *
293     * @return the first value, or null if the cursor range is empty.
294     */
295    V first(LockMode lockMode)
296        throws DatabaseException;
297
298    /**
299     * Moves the cursor to the last value and returns it, or returns null if
300     * the cursor range is empty.
301     *
302     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
303     *
304     * @return the last value, or null if the cursor range is empty.
305     */
306    V last()
307        throws DatabaseException;
308
309    /**
310     * Moves the cursor to the last value and returns it, or returns null if
311     * the cursor range is empty.
312     *
313     * @param lockMode the lock mode to use for this operation, or null to
314     * use {@link LockMode#DEFAULT}.
315     *
316     * @return the last value, or null if the cursor range is empty.
317     */
318    V last(LockMode lockMode)
319        throws DatabaseException;
320
321    /**
322     * Moves the cursor to the next value and returns it, or returns null
323     * if there are no more values in the cursor range.  If the cursor is
324     * uninitialized, this method is equivalent to {@link #first}.
325     *
326     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
327     *
328     * @return the next value, or null if there are no more values in the
329     * cursor range.
330     */
331    V next()
332        throws DatabaseException;
333
334    /**
335     * Moves the cursor to the next value and returns it, or returns null
336     * if there are no more values in the cursor range.  If the cursor is
337     * uninitialized, this method is equivalent to {@link #first}.
338     *
339     * @param lockMode the lock mode to use for this operation, or null to
340     * use {@link LockMode#DEFAULT}.
341     *
342     * @return the next value, or null if there are no more values in the
343     * cursor range.
344     */
345    V next(LockMode lockMode)
346        throws DatabaseException;
347
348    /**
349     * Moves the cursor to the next value with the same key (duplicate) and
350     * returns it, or returns null if no more values are present for the key at
351     * the current position.
352     *
353     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
354     *
355     * @return the next value with the same key, or null if no more values are
356     * present for the key at the current position.
357     *
358     * @throws IllegalStateException if the cursor is uninitialized.
359     */
360    V nextDup()
361        throws DatabaseException;
362
363    /**
364     * Moves the cursor to the next value with the same key (duplicate) and
365     * returns it, or returns null if no more values are present for the key at
366     * the current position.
367     *
368     * @param lockMode the lock mode to use for this operation, or null to
369     * use {@link LockMode#DEFAULT}.
370     *
371     * @return the next value with the same key, or null if no more values are
372     * present for the key at the current position.
373     *
374     * @throws IllegalStateException if the cursor is uninitialized.
375     */
376    V nextDup(LockMode lockMode)
377        throws DatabaseException;
378
379    /**
380     * Moves the cursor to the next value with a different key and returns it,
381     * or returns null if there are no more unique keys in the cursor range.
382     * If the cursor is uninitialized, this method is equivalent to {@link
383     * #first}.
384     *
385     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
386     *
387     * @return the next value with a different key, or null if there are no
388     * more unique keys in the cursor range.
389     */
390    V nextNoDup()
391        throws DatabaseException;
392
393    /**
394     * Moves the cursor to the next value with a different key and returns it,
395     * or returns null if there are no more unique keys in the cursor range.
396     * If the cursor is uninitialized, this method is equivalent to {@link
397     * #first}.
398     *
399     * @param lockMode the lock mode to use for this operation, or null to
400     * use {@link LockMode#DEFAULT}.
401     *
402     * @return the next value with a different key, or null if there are no
403     * more unique keys in the cursor range.
404     */
405    V nextNoDup(LockMode lockMode)
406        throws DatabaseException;
407
408    /**
409     * Moves the cursor to the previous value and returns it, or returns null
410     * if there are no preceding values in the cursor range.  If the cursor is
411     * uninitialized, this method is equivalent to {@link #last}.
412     *
413     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
414     *
415     * @return the previous value, or null if there are no preceding values in
416     * the cursor range.
417     */
418    V prev()
419        throws DatabaseException;
420
421    /**
422     * Moves the cursor to the previous value and returns it, or returns null
423     * if there are no preceding values in the cursor range.  If the cursor is
424     * uninitialized, this method is equivalent to {@link #last}.
425     *
426     * @param lockMode the lock mode to use for this operation, or null to
427     * use {@link LockMode#DEFAULT}.
428     *
429     * @return the previous value, or null if there are no preceding values in
430     * the cursor range.
431     */
432    V prev(LockMode lockMode)
433        throws DatabaseException;
434
435    /**
436     * Moves the cursor to the previous value with the same key (duplicate) and
437     * returns it, or returns null if no preceding values are present for the
438     * key at the current position.
439     *
440     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
441     *
442     * @return the previous value with the same key, or null if no preceding
443     * values are present for the key at the current position.
444     *
445     * @throws IllegalStateException if the cursor is uninitialized.
446     */
447    V prevDup()
448        throws DatabaseException;
449
450    /**
451     * Moves the cursor to the previous value with the same key (duplicate) and
452     * returns it, or returns null if no preceding values are present for the
453     * key at the current position.
454     *
455     * @param lockMode the lock mode to use for this operation, or null to
456     * use {@link LockMode#DEFAULT}.
457     *
458     * @return the previous value with the same key, or null if no preceding
459     * values are present for the key at the current position.
460     *
461     * @throws IllegalStateException if the cursor is uninitialized.
462     */
463    V prevDup(LockMode lockMode)
464        throws DatabaseException;
465
466    /**
467     * Moves the cursor to the preceding value with a different key and returns
468     * it, or returns null if there are no preceding unique keys in the cursor
469     * range.  If the cursor is uninitialized, this method is equivalent to
470     * {@link #last}.
471     *
472     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
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()
478        throws DatabaseException;
479
480    /**
481     * Moves the cursor to the preceding value with a different key and returns
482     * it, or returns null if there are no preceding unique keys in the cursor
483     * range.  If the cursor is uninitialized, this method is equivalent to
484     * {@link #last}.
485     *
486     * @param lockMode the lock mode to use for this operation, or null to
487     * use {@link LockMode#DEFAULT}.
488     *
489     * @return the previous value with a different key, or null if there are no
490     * preceding unique keys in the cursor range.
491     */
492    V prevNoDup(LockMode lockMode)
493        throws DatabaseException;
494
495    /**
496     * Returns the value at the cursor position, or null if the value at the
497     * cursor position has been deleted.
498     *
499     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
500     *
501     * @return the value at the cursor position, or null if it has been
502     * deleted.
503     *
504     * @throws IllegalStateException if the cursor is uninitialized.
505     */
506    V current()
507        throws DatabaseException;
508
509    /**
510     * Returns the value at the cursor position, or null if the value at the
511     * cursor position has been deleted.
512     *
513     * @param lockMode the lock mode to use for this operation, or null to
514     * use {@link LockMode#DEFAULT}.
515     *
516     * @return the value at the cursor position, or null if it has been
517     * deleted.
518     *
519     * @throws IllegalStateException if the cursor is uninitialized.
520     */
521    V current(LockMode lockMode)
522        throws DatabaseException;
523
524    /**
525     * Returns the number of values (duplicates) for the key at the cursor
526     * position, or returns zero if all values for the key have been deleted,
527     * Returns one or zero if the underlying index has unique keys.
528     *
529     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
530     *
531     * @return the number of duplicates, or zero if all values for the current
532     * key have been deleted.
533     *
534     * @throws IllegalStateException if the cursor is uninitialized.
535     */
536    int count()
537        throws DatabaseException;
538
539    /**
540     * Returns an iterator over the key range, starting with the value
541     * following the current position or at the first value if the cursor is
542     * uninitialized.
543     *
544     * <p>{@link LockMode#DEFAULT} is used implicitly.</p>
545     *
546     * @return the iterator.
547     */
548    Iterator<V> iterator();
549
550    /**
551     * Returns an iterator over the key range, starting with the value
552     * following the current position or at the first value if the cursor is
553     * uninitialized.
554     *
555     * @param lockMode the lock mode to use for all operations performed
556     * using the iterator, or null to use {@link LockMode#DEFAULT}.
557     *
558     * @return the iterator.
559     */
560    Iterator<V> iterator(LockMode lockMode);
561
562    /**
563     * Replaces the entity at the cursor position with the given entity.
564     *
565     * @param entity the entity to replace the entity at the current position.
566     *
567     * @return true if successful or false if the entity at the current
568     * position was previously deleted.
569     *
570     * @throws IllegalStateException if the cursor is uninitialized.
571     *
572     * @throws UnsupportedOperationException if the index is read only or if
573     * the value type is not an entity type.
574     */
575    boolean update(V entity)
576        throws DatabaseException;
577
578    /**
579     * Deletes the entity at the cursor position.
580     *
581     * @throws IllegalStateException if the cursor is uninitialized.
582     *
583     * @throws UnsupportedOperationException if the index is read only.
584     *
585     * @return true if successful or false if the entity at the current
586     * position has been deleted.
587     */
588    boolean delete()
589        throws DatabaseException;
590
591    /**
592     * Duplicates the cursor at the cursor position.  The returned cursor will
593     * be initially positioned at the same position as this current cursor, and
594     * will inherit this cursor's {@link Transaction} and {@link CursorConfig}.
595     *
596     * @return the duplicated cursor.
597     */
598    EntityCursor<V> dup()
599        throws DatabaseException;
600
601    /**
602     * Closes the cursor.
603     */
604    void close()
605        throws DatabaseException;
606}
607