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