001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.directory.server.core.partition.impl.btree.jdbm;
020    
021    
022    import jdbm.btree.BTree;
023    import jdbm.helper.Tuple;
024    import jdbm.helper.TupleBrowser;
025    
026    import java.util.Comparator;
027    
028    import org.apache.directory.shared.ldap.cursor.AbstractCursor;
029    import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
030    
031    
032    /**
033     * Cursor over the keys of a JDBM BTree.  Obviously does not return duplicate
034     * keys since JDBM does not natively support multiple values for the same key.
035     *
036     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037     * @version $Rev$, $Date$
038     */
039    public class KeyBTreeCursor<E> extends AbstractCursor<E>
040    {
041        private final Tuple tuple = new Tuple();
042    
043        private final BTree btree;
044        private final Comparator<E> comparator;
045        private boolean valueAvailable;
046        private TupleBrowser browser;
047    
048    
049        /**
050         * Creates a Cursor over the keys of a JDBM BTree.
051         *
052         * @param btree the JDBM BTree to build a Cursor over
053         * @param comparator the Comparator used to determine key ordering
054         * @throws Exception of there are problems accessing the BTree
055         */
056        public KeyBTreeCursor( BTree btree, Comparator<E> comparator ) throws Exception
057        {
058            this.btree = btree;
059            this.comparator = comparator;
060        }
061    
062    
063        private void clearValue()
064        {
065            tuple.setKey( null );
066            tuple.setValue( null );
067            valueAvailable = false;
068        }
069    
070    
071        public boolean available()
072        {
073            return valueAvailable;
074        }
075    
076    
077        public void before( E element ) throws Exception
078        {
079            checkNotClosed( "before()" );
080            browser = btree.browse( element );
081            clearValue();
082        }
083    
084    
085        @SuppressWarnings("unchecked")
086        public void after( E element ) throws Exception
087        {
088            browser = btree.browse( element );
089    
090            /*
091             * While the next value is less than or equal to the element keep
092             * advancing forward to the next item.  If we cannot advance any
093             * further then stop and return.  If we find a value greater than
094             * the element then we stop, backup, and return so subsequent calls
095             * to getNext() will return a value greater than the element.
096             */
097            while ( browser.getNext( tuple ) )
098            {
099                checkNotClosed( "after()" );
100                E next = ( E ) tuple.getKey();
101                int nextCompared = comparator.compare( next, element );
102    
103                if ( nextCompared <= 0 )
104                {
105                    // just continue
106                }
107                else 
108                {
109                    /*
110                     * If we just have values greater than the element argument
111                     * then we are before the first element and must backup to
112                     * before the first element state for the JDBM browser which 
113                     * apparently the browser supports.
114                     */
115                    browser.getPrevious( tuple );
116                    clearValue();
117                    return;
118                }
119            }
120    
121            clearValue();
122            // just return
123        }
124    
125    
126        public void beforeFirst() throws Exception
127        {
128            checkNotClosed( "beforeFirst()" );
129            browser = btree.browse();
130            clearValue();
131        }
132    
133    
134        public void afterLast() throws Exception
135        {
136            checkNotClosed( "afterLast()" );
137            browser = btree.browse( null );
138        }
139    
140    
141        public boolean first() throws Exception
142        {
143            beforeFirst();
144            return next();
145        }
146    
147    
148        public boolean last() throws Exception
149        {
150            afterLast();
151            return previous();
152        }
153    
154    
155        public boolean previous() throws Exception
156        {
157            checkNotClosed( "previous()" );
158            if ( browser == null )
159            {
160                browser = btree.browse( null );
161            }
162    
163            if ( browser.getPrevious( tuple ) )
164            {
165                return valueAvailable = true;
166            }
167            else
168            {
169                clearValue();
170                return false;
171            }
172        }
173    
174    
175        public boolean next() throws Exception
176        {
177            checkNotClosed( "next()" );
178            if ( browser == null )
179            {
180                browser = btree.browse();
181            }
182    
183            if ( browser.getNext( tuple ) )
184            {
185                return valueAvailable = true;
186            }
187            else
188            {
189                clearValue();
190                return false;
191            }
192        }
193    
194    
195        @SuppressWarnings("unchecked")
196        public E get() throws Exception
197        {
198            checkNotClosed( "get()" );
199            if ( valueAvailable )
200            {
201                return ( E ) tuple.getKey();
202            }
203    
204            throw new InvalidCursorPositionException();
205        }
206    
207    
208        public boolean isElementReused()
209        {
210            return false;
211        }
212    }