KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > util > keyrange > RangeCursor


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

8
9 package com.sleepycat.util.keyrange;
10
11 import com.sleepycat.compat.DbCompat;
12 import com.sleepycat.je.Cursor;
13 import com.sleepycat.je.DatabaseEntry;
14 import com.sleepycat.je.DatabaseException;
15 import com.sleepycat.je.LockMode;
16 import com.sleepycat.je.OperationStatus;
17 import com.sleepycat.je.SecondaryCursor;
18
19 /**
20  * A cursor-like interface that enforces a key range. The method signatures
21  * are actually those of SecondaryCursor, but the pKey parameter may be null.
22  * It was done this way to avoid doubling the number of methods.
23  *
24  * <p>This is not a fully general implementation of a range cursor and should
25  * not be used directly by applications; however, it may evolve into a
26  * generally useful range cursor some day.</p>
27  *
28  * @author Mark Hayes
29  */

30 public class RangeCursor implements Cloneable JavaDoc {
31
32     /**
33      * The cursor and secondary cursor are the same object. The secCursor is
34      * null if the database is not a secondary database.
35      */

36     private Cursor cursor;
37     private SecondaryCursor secCursor;
38
39     /**
40      * The range is always non-null, but may be unbounded meaning that it is
41      * open and not used.
42      */

43     private KeyRange range;
44
45     /**
46      * The pkRange may be non-null only if the range is a single-key range
47      * and the cursor is a secondary cursor. It further restricts the range of
48      * primary keys in a secondary database.
49      */

50     private KeyRange pkRange;
51
52     /**
53      * The privXxx entries are used only when the range is bounded. We read
54      * into these private entries to avoid modifying the caller's entry
55      * parameters in the case where we read successfully but the key is out of
56      * range. In that case we return NOTFOUND and we want to leave the entry
57      * parameters unchanged.
58      */

59     private DatabaseEntry privKey;
60     private DatabaseEntry privPKey;
61     private DatabaseEntry privData;
62
63     /**
64      * The initialized flag is set to true whenever we successfully position
65      * the cursor. It is used to implement the getNext/Prev logic for doing a
66      * getFirst/Last when the cursor is not initialized. We can't rely on
67      * Cursor to do that for us, since if we position the underlying cursor
68      * successfully but the key is out of range, we have no way to set the
69      * underlying cursor to uninitialized. A range cursor always starts in the
70      * uninitialized state.
71      */

72     private boolean initialized;
73
74     /**
75      * Creates a range cursor.
76      */

77     public RangeCursor(KeyRange range, Cursor cursor)
78         throws DatabaseException {
79
80         this.range = range;
81         this.cursor = cursor;
82         init();
83     }
84
85     /**
86      * Creates a range cursor with a duplicate range.
87      */

88     public RangeCursor(KeyRange range, KeyRange pkRange, Cursor cursor)
89         throws DatabaseException {
90
91         if (pkRange != null && !range.singleKey) {
92             throw new IllegalArgumentException JavaDoc();
93         }
94         this.range = range;
95         this.pkRange = pkRange;
96         this.cursor = cursor;
97         init();
98         if (pkRange != null && secCursor == null) {
99             throw new IllegalArgumentException JavaDoc();
100         }
101     }
102
103     /**
104      * Create a cloned range cursor. The caller must clone the underlying
105      * cursor before using this constructor, because cursor open/close is
106      * handled specially for CDS cursors outside this class.
107      */

108     public RangeCursor dup(boolean samePosition)
109         throws DatabaseException {
110
111         try {
112             RangeCursor c = (RangeCursor) super.clone();
113             c.cursor = dupCursor(cursor, samePosition);
114             c.init();
115             return c;
116         } catch (CloneNotSupportedException JavaDoc neverHappens) {
117             return null;
118         }
119     }
120
121     /**
122      * Used for opening and duping (cloning).
123      */

124     private void init() {
125
126         if (cursor instanceof SecondaryCursor) {
127             secCursor = (SecondaryCursor) cursor;
128         } else {
129             secCursor = null;
130         }
131
132         if (range.hasBound()) {
133             privKey = new DatabaseEntry();
134             privPKey = new DatabaseEntry();
135             privData = new DatabaseEntry();
136         } else {
137             privKey = null;
138             privPKey = null;
139             privData = null;
140         }
141     }
142
143     /**
144      * Returns whether the cursor is initialized at a valid position.
145      */

146     public boolean isInitialized() {
147         return initialized;
148     }
149
150     /**
151      * Returns the underlying cursor. Used for cloning.
152      */

153     public Cursor getCursor() {
154         return cursor;
155     }
156
157     /**
158      * When an unbounded range is used, this method is called to use the
159      * callers entry parameters directly, to avoid the extra step of copying
160      * between the private entries and the caller's entries.
161      */

162     private void setParams(DatabaseEntry key, DatabaseEntry pKey,
163                            DatabaseEntry data) {
164         privKey = key;
165         privPKey = pKey;
166         privData = data;
167     }
168
169     /**
170      * Dups the cursor, sets the cursor and secCursor fields to the duped
171      * cursor, and returns the old cursor. Always call endOperation in a
172      * finally clause after calling beginOperation.
173      *
174      * <p>If the returned cursor == the cursor field, the cursor is
175      * uninitialized and was not duped; this case is handled correctly by
176      * endOperation.</p>
177      */

178     private Cursor beginOperation()
179         throws DatabaseException {
180
181         Cursor oldCursor = cursor;
182         if (initialized) {
183             cursor = dupCursor(cursor, true);
184             if (secCursor != null) {
185                 secCursor = (SecondaryCursor) cursor;
186             }
187         } else {
188             return cursor;
189         }
190         return oldCursor;
191     }
192
193     /**
194      * If the operation succeded, leaves the duped cursor in place and closes
195      * the oldCursor. If the operation failed, moves the oldCursor back in
196      * place and closes the duped cursor. oldCursor may be null if
197      * beginOperation was not called, in cases where we don't need to dup
198      * the cursor. Always call endOperation when a successful operation ends,
199      * in order to set the initialized field.
200      */

201     private void endOperation(Cursor oldCursor, OperationStatus status,
202                               DatabaseEntry key, DatabaseEntry pKey,
203                               DatabaseEntry data)
204         throws DatabaseException {
205
206         if (status == OperationStatus.SUCCESS) {
207             if (oldCursor != null && oldCursor != cursor) {
208                 closeCursor(oldCursor);
209             }
210             if (key != null) {
211                 swapData(key, privKey);
212             }
213             if (pKey != null && secCursor != null) {
214                 swapData(pKey, privPKey);
215             }
216             if (data != null) {
217                 swapData(data, privData);
218             }
219             initialized = true;
220         } else {
221             if (oldCursor != null && oldCursor != cursor) {
222                 closeCursor(cursor);
223                 cursor = oldCursor;
224                 if (secCursor != null) {
225                     secCursor = (SecondaryCursor) cursor;
226                 }
227             }
228         }
229     }
230
231     /**
232      * Swaps the contents of the two entries. Used to return entry data to
233      * the caller when the operation was successful.
234      */

235     private static void swapData(DatabaseEntry e1, DatabaseEntry e2) {
236
237         byte[] d1 = e1.getData();
238         int o1 = e1.getOffset();
239         int s1 = e1.getSize();
240
241         e1.setData(e2.getData(), e2.getOffset(), e2.getSize());
242         e2.setData(d1, o1, s1);
243     }
244
245     /**
246      * Shares the same byte array, offset and size between two entries.
247      * Used when copying the entry data is not necessary because it is known
248      * that the underlying operation will not modify the entry, for example,
249      * with getSearchKey.
250      */

251     private static void shareData(DatabaseEntry from, DatabaseEntry to) {
252
253         if (from != null) {
254             to.setData(from.getData(), from.getOffset(), from.getSize());
255         }
256     }
257
258     public OperationStatus getFirst(DatabaseEntry key,
259                                     DatabaseEntry pKey,
260                                     DatabaseEntry data,
261                                     LockMode lockMode)
262         throws DatabaseException {
263
264         OperationStatus status;
265         if (!range.hasBound()) {
266             setParams(key, pKey, data);
267             status = doGetFirst(lockMode);
268             endOperation(null, status, null, null, null);
269             return status;
270         }
271         if (pkRange != null) {
272             KeyRange.copy(range.beginKey, privKey);
273             if (pkRange.singleKey) {
274                 KeyRange.copy(pkRange.beginKey, privPKey);
275                 status = doGetSearchBoth(lockMode);
276                 endOperation(null, status, key, pKey, data);
277             } else {
278                 status = OperationStatus.NOTFOUND;
279                 Cursor oldCursor = beginOperation();
280                 try {
281                     if (pkRange.beginKey == null) {
282                         status = doGetSearchKey(lockMode);
283                     } else {
284                         KeyRange.copy(pkRange.beginKey, privPKey);
285                         status = doGetSearchBothRange(lockMode);
286                         if (status == OperationStatus.SUCCESS &&
287                             !pkRange.beginInclusive &&
288                             pkRange.compare(privPKey, pkRange.beginKey) == 0) {
289                             status = doGetNextDup(lockMode);
290                         }
291                     }
292                     if (status == OperationStatus.SUCCESS &&
293                         !pkRange.check(privPKey)) {
294                         status = OperationStatus.NOTFOUND;
295                     }
296                 } finally {
297                     endOperation(oldCursor, status, key, pKey, data);
298                 }
299             }
300         } else if (range.singleKey) {
301             KeyRange.copy(range.beginKey, privKey);
302             status = doGetSearchKey(lockMode);
303             endOperation(null, status, key, pKey, data);
304         } else {
305             status = OperationStatus.NOTFOUND;
306             Cursor oldCursor = beginOperation();
307             try {
308                 if (range.beginKey == null) {
309                     status = doGetFirst(lockMode);
310                 } else {
311                     KeyRange.copy(range.beginKey, privKey);
312                     status = doGetSearchKeyRange(lockMode);
313                     if (status == OperationStatus.SUCCESS &&
314                         !range.beginInclusive &&
315                         range.compare(privKey, range.beginKey) == 0) {
316                         status = doGetNextNoDup(lockMode);
317                     }
318                 }
319                 if (status == OperationStatus.SUCCESS &&
320                     !range.check(privKey)) {
321                     status = OperationStatus.NOTFOUND;
322                 }
323             } finally {
324                 endOperation(oldCursor, status, key, pKey, data);
325             }
326         }
327         return status;
328     }
329
330     public OperationStatus getLast(DatabaseEntry key,
331                                    DatabaseEntry pKey,
332                                    DatabaseEntry data,
333                                    LockMode lockMode)
334         throws DatabaseException {
335
336         OperationStatus status = OperationStatus.NOTFOUND;
337         if (!range.hasBound()) {
338             setParams(key, pKey, data);
339             status = doGetLast(lockMode);
340             endOperation(null, status, null, null, null);
341             return status;
342         }
343         Cursor oldCursor = beginOperation();
344         try {
345             if (pkRange != null) {
346                 KeyRange.copy(range.beginKey, privKey);
347                 boolean doLast = false;
348                 if (pkRange.endKey == null) {
349                     doLast = true;
350                 } else {
351                     KeyRange.copy(pkRange.endKey, privPKey);
352                     status = doGetSearchBothRange(lockMode);
353                     if (status == OperationStatus.SUCCESS) {
354                         if (!pkRange.endInclusive ||
355                             pkRange.compare(pkRange.endKey, privPKey) != 0) {
356                             status = doGetPrevDup(lockMode);
357                         }
358                     } else {
359                         KeyRange.copy(range.beginKey, privKey);
360                         doLast = true;
361                     }
362                 }
363                 if (doLast) {
364                     status = doGetSearchKey(lockMode);
365                     if (status == OperationStatus.SUCCESS) {
366                         status = doGetNextNoDup(lockMode);
367                         if (status == OperationStatus.SUCCESS) {
368                             status = doGetPrev(lockMode);
369                         } else {
370                             status = doGetLast(lockMode);
371                         }
372                     }
373                 }
374                 if (status == OperationStatus.SUCCESS &&
375                     !pkRange.check(privPKey)) {
376                     status = OperationStatus.NOTFOUND;
377                 }
378             } else if (range.endKey == null) {
379                 status = doGetLast(lockMode);
380             } else {
381                 KeyRange.copy(range.endKey, privKey);
382                 status = doGetSearchKeyRange(lockMode);
383                 if (status == OperationStatus.SUCCESS) {
384                     if (range.endInclusive &&
385                         range.compare(range.endKey, privKey) == 0) {
386                         /* Skip this step if dups are not configured? */
387                         status = doGetNextNoDup(lockMode);
388                         if (status == OperationStatus.SUCCESS) {
389                             status = doGetPrev(lockMode);
390                         } else {
391                             status = doGetLast(lockMode);
392                         }
393                     } else {
394                         status = doGetPrev(lockMode);
395                     }
396                 } else {
397                     status = doGetLast(lockMode);
398                 }
399             }
400             if (status == OperationStatus.SUCCESS &&
401                 !range.checkBegin(privKey, true)) {
402                 status = OperationStatus.NOTFOUND;
403             }
404         } finally {
405             endOperation(oldCursor, status, key, pKey, data);
406         }
407         return status;
408     }
409
410     public OperationStatus getNext(DatabaseEntry key,
411                                    DatabaseEntry pKey,
412                                    DatabaseEntry data,
413                                    LockMode lockMode)
414         throws DatabaseException {
415
416         OperationStatus status;
417         if (!initialized) {
418             return getFirst(key, pKey, data, lockMode);
419         }
420         if (!range.hasBound()) {
421             setParams(key, pKey, data);
422             status = doGetNext(lockMode);
423             endOperation(null, status, null, null, null);
424             return status;
425         }
426         if (pkRange != null) {
427             if (pkRange.endKey == null) {
428                 status = doGetNextDup(lockMode);
429                 endOperation(null, status, key, pKey, data);
430             } else {
431                 status = OperationStatus.NOTFOUND;
432                 Cursor oldCursor = beginOperation();
433                 try {
434                     status = doGetNextDup(lockMode);
435                     if (status == OperationStatus.SUCCESS &&
436                         !pkRange.checkEnd(privPKey, true)) {
437                         status = OperationStatus.NOTFOUND;
438                     }
439                 } finally {
440                     endOperation(oldCursor, status, key, pKey, data);
441                 }
442             }
443         } else if (range.singleKey) {
444             status = doGetNextDup(lockMode);
445             endOperation(null, status, key, pKey, data);
446         } else {
447             status = OperationStatus.NOTFOUND;
448             Cursor oldCursor = beginOperation();
449             try {
450                 status = doGetNext(lockMode);
451                 if (status == OperationStatus.SUCCESS &&
452                     !range.check(privKey)) {
453                     status = OperationStatus.NOTFOUND;
454                 }
455             } finally {
456                 endOperation(oldCursor, status, key, pKey, data);
457             }
458         }
459         return status;
460     }
461
462     public OperationStatus getNextNoDup(DatabaseEntry key,
463                                         DatabaseEntry pKey,
464                                         DatabaseEntry data,
465                                         LockMode lockMode)
466         throws DatabaseException {
467
468         OperationStatus status;
469         if (!initialized) {
470             return getFirst(key, pKey, data, lockMode);
471         }
472         if (!range.hasBound()) {
473             setParams(key, pKey, data);
474             status = doGetNextNoDup(lockMode);
475             endOperation(null, status, null, null, null);
476             return status;
477         }
478         if (range.singleKey) {
479             status = OperationStatus.NOTFOUND;
480         } else {
481             status = OperationStatus.NOTFOUND;
482             Cursor oldCursor = beginOperation();
483             try {
484                 status = doGetNextNoDup(lockMode);
485                 if (status == OperationStatus.SUCCESS &&
486                     !range.check(privKey)) {
487                     status = OperationStatus.NOTFOUND;
488                 }
489             } finally {
490                 endOperation(oldCursor, status, key, pKey, data);
491             }
492         }
493         return status;
494     }
495
496     public OperationStatus getPrev(DatabaseEntry key,
497                                    DatabaseEntry pKey,
498                                    DatabaseEntry data,
499                                    LockMode lockMode)
500         throws DatabaseException {
501
502         OperationStatus status;
503         if (!initialized) {
504             return getLast(key, pKey, data, lockMode);
505         }
506         if (!range.hasBound()) {
507             setParams(key, pKey, data);
508             status = doGetPrev(lockMode);
509             endOperation(null, status, null, null, null);
510             return status;
511         }
512         if (pkRange != null) {
513             if (pkRange.beginKey == null) {
514                 status = doGetPrevDup(lockMode);
515                 endOperation(null, status, key, pKey, data);
516             } else {
517                 status = OperationStatus.NOTFOUND;
518                 Cursor oldCursor = beginOperation();
519                 try {
520                     status = doGetPrevDup(lockMode);
521                     if (status == OperationStatus.SUCCESS &&
522                         !pkRange.checkBegin(privPKey, true)) {
523                         status = OperationStatus.NOTFOUND;
524                     }
525                 } finally {
526                     endOperation(oldCursor, status, key, pKey, data);
527                 }
528             }
529         } else if (range.singleKey) {
530             status = doGetPrevDup(lockMode);
531             endOperation(null, status, key, pKey, data);
532         } else {
533             status = OperationStatus.NOTFOUND;
534             Cursor oldCursor = beginOperation();
535             try {
536                 status = doGetPrev(lockMode);
537                 if (status == OperationStatus.SUCCESS &&
538                     !range.check(privKey)) {
539                     status = OperationStatus.NOTFOUND;
540                 }
541             } finally {
542                 endOperation(oldCursor, status, key, pKey, data);
543             }
544         }
545         return status;
546     }
547
548     public OperationStatus getPrevNoDup(DatabaseEntry key,
549                                         DatabaseEntry pKey,
550                                         DatabaseEntry data,
551                                         LockMode lockMode)
552         throws DatabaseException {
553
554         OperationStatus status;
555         if (!initialized) {
556             return getLast(key, pKey, data, lockMode);
557         }
558         if (!range.hasBound()) {
559             setParams(key, pKey, data);
560             status = doGetPrevNoDup(lockMode);
561             endOperation(null, status, null, null, null);
562             return status;
563         }
564         if (range.singleKey) {
565             status = OperationStatus.NOTFOUND;
566         } else {
567             status = OperationStatus.NOTFOUND;
568             Cursor oldCursor = beginOperation();
569             try {
570                 status = doGetPrevNoDup(lockMode);
571                 if (status == OperationStatus.SUCCESS &&
572                     !range.check(privKey)) {
573                     status = OperationStatus.NOTFOUND;
574                 }
575             } finally {
576                 endOperation(oldCursor, status, key, pKey, data);
577             }
578         }
579         return status;
580     }
581
582     public OperationStatus getSearchKey(DatabaseEntry key,
583                                         DatabaseEntry pKey,
584                                         DatabaseEntry data,
585                                         LockMode lockMode)
586         throws DatabaseException {
587
588         OperationStatus status;
589         if (!range.hasBound()) {
590             setParams(key, pKey, data);
591             status = doGetSearchKey(lockMode);
592             endOperation(null, status, null, null, null);
593             return status;
594         }
595         if (!range.check(key)) {
596             status = OperationStatus.NOTFOUND;
597         } else if (pkRange != null) {
598             status = OperationStatus.NOTFOUND;
599             Cursor oldCursor = beginOperation();
600             try {
601                 shareData(key, privKey);
602                 status = doGetSearchKey(lockMode);
603                 if (status == OperationStatus.SUCCESS &&
604                     !pkRange.check(privPKey)) {
605                     status = OperationStatus.NOTFOUND;
606                 }
607             } finally {
608                 endOperation(oldCursor, status, key, pKey, data);
609             }
610         } else {
611             shareData(key, privKey);
612             status = doGetSearchKey(lockMode);
613             endOperation(null, status, key, pKey, data);
614         }
615         return status;
616     }
617
618     public OperationStatus getSearchBoth(DatabaseEntry key,
619                                          DatabaseEntry pKey,
620                                          DatabaseEntry data,
621                                          LockMode lockMode)
622         throws DatabaseException {
623
624         OperationStatus status;
625         if (!range.hasBound()) {
626             setParams(key, pKey, data);
627             status = doGetSearchBoth(lockMode);
628             endOperation(null, status, null, null, null);
629             return status;
630         }
631         if (!range.check(key) ||
632             (pkRange != null && !pkRange.check(pKey))) {
633             status = OperationStatus.NOTFOUND;
634         } else {
635             shareData(key, privKey);
636             if (secCursor != null) {
637                 shareData(pKey, privPKey);
638             } else {
639                 shareData(data, privData);
640             }
641             status = doGetSearchBoth(lockMode);
642             endOperation(null, status, key, pKey, data);
643         }
644         return status;
645     }
646
647     public OperationStatus getSearchKeyRange(DatabaseEntry key,
648                                              DatabaseEntry pKey,
649                                              DatabaseEntry data,
650                                              LockMode lockMode)
651         throws DatabaseException {
652
653         OperationStatus status = OperationStatus.NOTFOUND;
654         if (!range.hasBound()) {
655             setParams(key, pKey, data);
656             status = doGetSearchKeyRange(lockMode);
657             endOperation(null, status, null, null, null);
658             return status;
659         }
660         Cursor oldCursor = beginOperation();
661         try {
662             shareData(key, privKey);
663             status = doGetSearchKeyRange(lockMode);
664             if (status == OperationStatus.SUCCESS &&
665                 (!range.check(privKey) ||
666                  (pkRange != null && !pkRange.check(pKey)))) {
667                 status = OperationStatus.NOTFOUND;
668             }
669         } finally {
670             endOperation(oldCursor, status, key, pKey, data);
671         }
672         return status;
673     }
674
675     public OperationStatus getSearchBothRange(DatabaseEntry key,
676                                               DatabaseEntry pKey,
677                                               DatabaseEntry data,
678                                               LockMode lockMode)
679         throws DatabaseException {
680
681         OperationStatus status = OperationStatus.NOTFOUND;
682         if (!range.hasBound()) {
683             setParams(key, pKey, data);
684             status = doGetSearchBothRange(lockMode);
685             endOperation(null, status, null, null, null);
686             return status;
687         }
688         Cursor oldCursor = beginOperation();
689         try {
690             shareData(key, privKey);
691             if (secCursor != null) {
692                 shareData(pKey, privPKey);
693             } else {
694                 shareData(data, privData);
695             }
696             status = doGetSearchBothRange(lockMode);
697             if (status == OperationStatus.SUCCESS &&
698                 (!range.check(privKey) ||
699                  (pkRange != null && !pkRange.check(pKey)))) {
700                 status = OperationStatus.NOTFOUND;
701             }
702         } finally {
703             endOperation(oldCursor, status, key, pKey, data);
704         }
705         return status;
706     }
707
708     public OperationStatus getSearchRecordNumber(DatabaseEntry key,
709                                                  DatabaseEntry pKey,
710                                                  DatabaseEntry data,
711                                                  LockMode lockMode)
712         throws DatabaseException {
713
714         OperationStatus status;
715         if (!range.hasBound()) {
716             setParams(key, pKey, data);
717             status = doGetSearchRecordNumber(lockMode);
718             endOperation(null, status, null, null, null);
719             return status;
720         }
721         if (!range.check(key)) {
722             status = OperationStatus.NOTFOUND;
723         } else {
724             shareData(key, privKey);
725             status = doGetSearchRecordNumber(lockMode);
726             endOperation(null, status, key, pKey, data);
727         }
728         return status;
729     }
730
731     public OperationStatus getNextDup(DatabaseEntry key,
732                                       DatabaseEntry pKey,
733                                       DatabaseEntry data,
734                                       LockMode lockMode)
735         throws DatabaseException {
736
737         if (!initialized) {
738             throw new DatabaseException("Cursor not initialized");
739         }
740         OperationStatus status;
741         if (!range.hasBound()) {
742             setParams(key, pKey, data);
743             status = doGetNextDup(lockMode);
744             endOperation(null, status, null, null, null);
745         } else if (pkRange != null && pkRange.endKey != null) {
746             status = OperationStatus.NOTFOUND;
747             Cursor oldCursor = beginOperation();
748             try {
749                 status = doGetNextDup(lockMode);
750                 if (status == OperationStatus.SUCCESS &&
751                     !pkRange.checkEnd(privPKey, true)) {
752                     status = OperationStatus.NOTFOUND;
753                 }
754             } finally {
755                 endOperation(oldCursor, status, key, pKey, data);
756             }
757         } else {
758             status = doGetNextDup(lockMode);
759             endOperation(null, status, key, pKey, data);
760         }
761         return status;
762     }
763
764     public OperationStatus getPrevDup(DatabaseEntry key,
765                                       DatabaseEntry pKey,
766                                       DatabaseEntry data,
767                                       LockMode lockMode)
768         throws DatabaseException {
769
770         if (!initialized) {
771             throw new DatabaseException("Cursor not initialized");
772         }
773         OperationStatus status;
774         if (!range.hasBound()) {
775             setParams(key, pKey, data);
776             status = doGetPrevDup(lockMode);
777             endOperation(null, status, null, null, null);
778         } else if (pkRange != null && pkRange.beginKey != null) {
779             status = OperationStatus.NOTFOUND;
780             Cursor oldCursor = beginOperation();
781             try {
782                 status = doGetPrevDup(lockMode);
783                 if (status == OperationStatus.SUCCESS &&
784                     !pkRange.checkBegin(privPKey, true)) {
785                     status = OperationStatus.NOTFOUND;
786                 }
787             } finally {
788                 endOperation(oldCursor, status, key, pKey, data);
789             }
790         } else {
791             status = doGetPrevDup(lockMode);
792             endOperation(null, status, key, pKey, data);
793         }
794         return status;
795     }
796
797     public OperationStatus getCurrent(DatabaseEntry key,
798                                       DatabaseEntry pKey,
799                                       DatabaseEntry data,
800                                       LockMode lockMode)
801         throws DatabaseException {
802
803         if (!initialized) {
804             throw new DatabaseException("Cursor not initialized");
805         }
806         if (secCursor != null && pKey != null) {
807             return secCursor.getCurrent(key, pKey, data, lockMode);
808         } else {
809             return cursor.getCurrent(key, data, lockMode);
810         }
811     }
812
813     /*
814      * Pass-thru methods.
815      */

816
817     public void close()
818         throws DatabaseException {
819
820         closeCursor(cursor);
821     }
822
823     public int count()
824         throws DatabaseException {
825
826     return cursor.count();
827     }
828
829     public OperationStatus delete()
830         throws DatabaseException {
831
832     return cursor.delete();
833     }
834
835     public OperationStatus put(DatabaseEntry key, DatabaseEntry data)
836         throws DatabaseException {
837
838         return cursor.put(key, data);
839     }
840
841     public OperationStatus putNoOverwrite(DatabaseEntry key,
842                                           DatabaseEntry data)
843         throws DatabaseException {
844
845         return cursor.putNoOverwrite(key, data);
846     }
847
848     public OperationStatus putNoDupData(DatabaseEntry key, DatabaseEntry data)
849         throws DatabaseException {
850
851         return cursor.putNoDupData(key, data);
852     }
853
854     public OperationStatus putCurrent(DatabaseEntry data)
855         throws DatabaseException {
856
857         return cursor.putCurrent(data);
858     }
859
860     public OperationStatus putAfter(DatabaseEntry key, DatabaseEntry data)
861         throws DatabaseException {
862
863         return DbCompat.putAfter(cursor, key, data);
864     }
865
866     public OperationStatus putBefore(DatabaseEntry key, DatabaseEntry data)
867         throws DatabaseException {
868
869         return DbCompat.putBefore(cursor, key, data);
870     }
871
872     private OperationStatus doGetFirst(LockMode lockMode)
873         throws DatabaseException {
874
875         if (secCursor != null && privPKey != null) {
876             return secCursor.getFirst(privKey, privPKey, privData, lockMode);
877         } else {
878             return cursor.getFirst(privKey, privData, lockMode);
879         }
880     }
881
882     private OperationStatus doGetLast(LockMode lockMode)
883         throws DatabaseException {
884
885         if (secCursor != null && privPKey != null) {
886             return secCursor.getLast(privKey, privPKey, privData, lockMode);
887         } else {
888             return cursor.getLast(privKey, privData, lockMode);
889         }
890     }
891
892     private OperationStatus doGetNext(LockMode lockMode)
893         throws DatabaseException {
894
895         if (secCursor != null && privPKey != null) {
896             return secCursor.getNext(privKey, privPKey, privData, lockMode);
897         } else {
898             return cursor.getNext(privKey, privData, lockMode);
899         }
900     }
901
902     private OperationStatus doGetNextDup(LockMode lockMode)
903         throws DatabaseException {
904
905         if (secCursor != null && privPKey != null) {
906             return secCursor.getNextDup(privKey, privPKey, privData, lockMode);
907         } else {
908             return cursor.getNextDup(privKey, privData, lockMode);
909         }
910     }
911
912     private OperationStatus doGetNextNoDup(LockMode lockMode)
913         throws DatabaseException {
914
915         if (secCursor != null && privPKey != null) {
916             return secCursor.getNextNoDup(privKey, privPKey, privData,
917                                           lockMode);
918         } else {
919             return cursor.getNextNoDup(privKey, privData, lockMode);
920         }
921     }
922
923     private OperationStatus doGetPrev(LockMode lockMode)
924         throws DatabaseException {
925
926         if (secCursor != null && privPKey != null) {
927             return secCursor.getPrev(privKey, privPKey, privData, lockMode);
928         } else {
929             return cursor.getPrev(privKey, privData, lockMode);
930         }
931     }
932
933     private OperationStatus doGetPrevDup(LockMode lockMode)
934         throws DatabaseException {
935
936         if (secCursor != null && privPKey != null) {
937             return secCursor.getPrevDup(privKey, privPKey, privData, lockMode);
938         } else {
939             return cursor.getPrevDup(privKey, privData, lockMode);
940         }
941     }
942
943     private OperationStatus doGetPrevNoDup(LockMode lockMode)
944         throws DatabaseException {
945
946         if (secCursor != null && privPKey != null) {
947             return secCursor.getPrevNoDup(privKey, privPKey, privData,
948                                           lockMode);
949         } else {
950             return cursor.getPrevNoDup(privKey, privData, lockMode);
951         }
952     }
953
954     private OperationStatus doGetSearchKey(LockMode lockMode)
955         throws DatabaseException {
956
957         if (checkRecordNumber() && DbCompat.getRecordNumber(privKey) <= 0) {
958             return OperationStatus.NOTFOUND;
959         }
960         if (secCursor != null && privPKey != null) {
961             return secCursor.getSearchKey(privKey, privPKey, privData,
962                                           lockMode);
963         } else {
964             return cursor.getSearchKey(privKey, privData, lockMode);
965         }
966     }
967
968     private OperationStatus doGetSearchKeyRange(LockMode lockMode)
969         throws DatabaseException {
970
971         if (checkRecordNumber() && DbCompat.getRecordNumber(privKey) <= 0) {
972             return OperationStatus.NOTFOUND;
973         }
974         if (secCursor != null && privPKey != null) {
975             return secCursor.getSearchKeyRange(privKey, privPKey, privData,
976                                                lockMode);
977         } else {
978             return cursor.getSearchKeyRange(privKey, privData, lockMode);
979         }
980     }
981
982     private OperationStatus doGetSearchBoth(LockMode lockMode)
983         throws DatabaseException {
984
985         if (checkRecordNumber() && DbCompat.getRecordNumber(privKey) <= 0) {
986             return OperationStatus.NOTFOUND;
987         }
988         if (secCursor != null && privPKey != null) {
989             return secCursor.getSearchBoth(privKey, privPKey, privData,
990                                            lockMode);
991         } else {
992             return cursor.getSearchBoth(privKey, privData, lockMode);
993         }
994     }
995
996     private OperationStatus doGetSearchBothRange(LockMode lockMode)
997         throws DatabaseException {
998
999         if (checkRecordNumber() && DbCompat.getRecordNumber(privKey) <= 0) {
1000            return OperationStatus.NOTFOUND;
1001        }
1002        if (secCursor != null && privPKey != null) {
1003            return secCursor.getSearchBothRange(privKey, privPKey, privData,
1004                                                lockMode);
1005        } else {
1006            return cursor.getSearchBothRange(privKey, privData, lockMode);
1007        }
1008    }
1009
1010    private OperationStatus doGetSearchRecordNumber(LockMode lockMode)
1011        throws DatabaseException {
1012
1013        if (DbCompat.getRecordNumber(privKey) <= 0) {
1014            return OperationStatus.NOTFOUND;
1015        }
1016        if (secCursor != null && privPKey != null) {
1017            return DbCompat.getSearchRecordNumber(secCursor, privKey, privPKey,
1018                                                  privData, lockMode);
1019        } else {
1020            return DbCompat.getSearchRecordNumber(cursor, privKey, privData,
1021                                                  lockMode);
1022        }
1023    }
1024
1025    /*
1026     * Protected methods for duping and closing cursors. These are overridden
1027     * by the collections API to implement cursor pooling for CDS.
1028     */

1029
1030    /**
1031     * Dups the given cursor.
1032     */

1033    protected Cursor dupCursor(Cursor cursor, boolean samePosition)
1034        throws DatabaseException {
1035
1036        return cursor.dup(samePosition);
1037    }
1038
1039    /**
1040     * Closes the given cursor.
1041     */

1042    protected void closeCursor(Cursor cursor)
1043        throws DatabaseException {
1044
1045        cursor.close();
1046    }
1047
1048    /**
1049     * If the database is a RECNO or QUEUE database, we know its keys are
1050     * record numbers. We treat a non-positive record number as out of bounds,
1051     * that is, we return NOTFOUND rather than throwing
1052     * IllegalArgumentException as would happen if we passed a non-positive
1053     * record number into the DB cursor. This behavior is required by the
1054     * collections interface.
1055     */

1056    protected boolean checkRecordNumber() {
1057        return false;
1058    }
1059}
1060
Popular Tags