KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > persist > EntityCursor


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

8
9 package com.sleepycat.persist;
10
11 import java.util.Iterator JavaDoc;
12
13 import com.sleepycat.je.CursorConfig;
14 import com.sleepycat.je.DatabaseException;
15 import com.sleepycat.je.LockMode;
16 import com.sleepycat.je.Transaction;
17 import com.sleepycat.persist.model.Relationship;
18 import 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  */

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()
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 JavaDoc<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 JavaDoc<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
Popular Tags