View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.directory.server.core.partition.impl.btree.mavibot;
20  
21  
22  import java.io.IOException;
23  
24  import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
25  import org.apache.directory.api.ldap.model.cursor.CursorException;
26  import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
27  import org.apache.directory.api.ldap.model.cursor.Tuple;
28  import org.apache.directory.api.ldap.model.exception.LdapException;
29  import org.apache.directory.mavibot.btree.TupleCursor;
30  import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
31  import org.apache.directory.server.i18n.I18n;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * Cursor over the Tuples of a Mavibot BTree. If the BTree allows duplicate values,
38   * we will browse each value and return a Tuple for each one of them.
39   *
40   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
41   */
42  class MavibotCursor<K, V> extends AbstractCursor<Tuple<K, V>>
43  {
44      /** A dedicated log for cursors */
45      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( "CURSOR" );
46  
47      /** The table we are building a cursor over */
48      private final MavibotTable<K, V> table;
49  
50      /** The tuple which will be returned */
51      private Tuple<K, V> returnedTuple = new Tuple<>();
52  
53      /** A flag set when there is a Tuple available */
54      private boolean valueAvailable = false;
55  
56      /** The Tuple browser */
57      private TupleCursor<K, V> browser;
58  
59  
60      /**
61       * Creates a Cursor over the tuples of a Mavibot table.
62       *
63       * @param table the JDBM Table to build a Cursor over
64       */
65      MavibotCursor( MavibotTable<K, V> table )
66      {
67          LOG_CURSOR.debug( "Creating MavibotCursor {}", this );
68          this.table = table;
69      }
70  
71  
72      /**
73       * Cleanup the returned tuple before reusing it.
74       */
75      private void clearValue()
76      {
77          returnedTuple.setKey( null );
78          returnedTuple.setValue( null );
79          valueAvailable = false;
80      }
81  
82  
83      /**
84       * {@inheritDoc}
85       */
86      public boolean available()
87      {
88          return valueAvailable;
89      }
90  
91  
92      /**
93       * Sets the position before a given key
94       * @param key The key we want to start with
95       * @throws LdapException 
96       * @throws CursorException
97       */
98      public void beforeKey( K key ) throws CursorException
99      {
100         checkNotClosed();
101         closeBrowser( browser );
102 
103         try
104         {
105             browser = table.getBTree().browseFrom( key );
106         }
107         catch ( IOException e )
108         {
109             throw new CursorException( e );
110         }
111 
112         clearValue();
113     }
114 
115 
116     /**
117      * Sets the position before a given key
118      * @param key The key we want to start with
119      * @throws LdapException 
120      * @throws CursorException
121      */
122     public void afterKey( K key ) throws CursorException
123     {
124         checkNotClosed();
125 
126         closeBrowser( browser );
127         try
128         {
129             browser = table.getBTree().browseFrom( key );
130 
131             if ( table.isDupsEnabled() )
132             {
133                 browser.nextKey();
134             }
135             else
136             {
137                 if ( browser.hasNextKey() )
138                 {
139                     browser.nextKey();
140                 }
141                 else
142                 {
143                     browser.afterLast();
144                 }
145             }
146 
147             clearValue();
148         }
149         catch ( IOException e )
150         {
151             clearValue();
152             throw new CursorException( e );
153         }
154     }
155 
156 
157     /**
158      * Sets the position before a given key and a given value for this key
159      * @param key The key we want to start with
160      * @param value The value we want to start with
161      * @throws LdapException 
162      * @throws CursorException
163      */
164     public void beforeValue( K key, V value ) throws LdapException, CursorException
165     {
166         throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
167     }
168 
169 
170     /**
171      * Sets the position after a given key and a given value for this key
172      * @param key The key we want to start with
173      * @param value The value we want to start with
174      * @throws LdapException 
175      * @throws CursorException
176      */
177     public void afterValue( K key, V value ) throws LdapException, CursorException
178     {
179         throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
180     }
181 
182 
183     /**
184      * {@inheritDoc}
185      */
186     public void before( Tuple<K, V> element ) throws LdapException, CursorException
187     {
188         beforeKey( element.getKey() );
189     }
190 
191 
192     /**
193      * {@inheritDoc}
194      */
195     public void after( Tuple<K, V> element ) throws LdapException, CursorException
196     {
197         afterKey( element.getKey() );
198     }
199 
200 
201     /**
202      * {@inheritDoc}
203      */
204     public void beforeFirst() throws LdapException, CursorException
205     {
206         checkNotClosed();
207 
208         try
209         {
210             if ( browser == null )
211             {
212                 browser = table.getBTree().browse();
213             }
214 
215             browser.beforeFirst();
216             clearValue();
217         }
218         catch ( IOException e )
219         {
220             throw new CursorException( e );
221         }
222         catch ( KeyNotFoundException knfe )
223         {
224             throw new CursorException( knfe );
225         }
226     }
227 
228 
229     /**
230      * {@inheritDoc}
231      */
232     public void afterLast() throws LdapException, CursorException
233     {
234         checkNotClosed();
235 
236         try
237         {
238             if ( browser == null )
239             {
240                 browser = table.getBTree().browse();
241             }
242 
243             browser.afterLast();
244             clearValue();
245         }
246         catch ( IOException e )
247         {
248             throw new CursorException( e );
249         }
250         catch ( KeyNotFoundException knfe )
251         {
252             throw new CursorException( knfe );
253         }
254     }
255 
256 
257     /**
258      * {@inheritDoc}
259      */
260     public boolean first() throws LdapException, CursorException
261     {
262         beforeFirst();
263 
264         return next();
265     }
266 
267 
268     /**
269      * {@inheritDoc}
270      */
271     public boolean last() throws LdapException, CursorException
272     {
273         afterLast();
274         return previous();
275     }
276 
277 
278     /**
279      * {@inheritDoc}
280      */
281     public boolean previous() throws LdapException, CursorException
282     {
283         checkNotClosed();
284         if ( browser == null )
285         {
286             afterLast();
287         }
288 
289         try
290         {
291             if ( browser.hasPrev() )
292             {
293                 org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.prev();
294 
295                 returnedTuple.setKey( tuple.getKey() );
296                 returnedTuple.setValue( tuple.getValue() );
297                 valueAvailable = true;
298                 return true;
299             }
300             else
301             {
302                 clearValue();
303                 return false;
304             }
305         }
306         catch ( IOException e )
307         {
308             throw new CursorException( e );
309         }
310     }
311 
312 
313     /**
314      * {@inheritDoc}
315      */
316     public boolean next() throws LdapException, CursorException
317     {
318         checkNotClosed();
319 
320         if ( browser == null )
321         {
322             beforeFirst();
323         }
324 
325         try
326         {
327             if ( browser.hasNext() )
328             {
329                 org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.next();
330 
331                 returnedTuple.setKey( tuple.getKey() );
332                 returnedTuple.setValue( tuple.getValue() );
333                 valueAvailable = true;
334                 return true;
335             }
336             else
337             {
338                 clearValue();
339                 return false;
340             }
341         }
342         catch ( IOException e )
343         {
344             throw new CursorException( e );
345         }
346     }
347 
348 
349     /**
350      * {@inheritDoc}
351      */
352     public Tuple<K, V> get() throws CursorException
353     {
354         checkNotClosed();
355         if ( valueAvailable )
356         {
357             return returnedTuple;
358         }
359 
360         throw new InvalidCursorPositionException();
361     }
362 
363 
364     /**
365      * {@inheritDoc}
366      */
367     @Override
368     public void close() throws IOException
369     {
370         LOG_CURSOR.debug( "Closing MavibotCursor {}", this );
371         super.close();
372         closeBrowser( browser );
373     }
374 
375 
376     /**
377      * {@inheritDoc}
378      */
379     @Override
380     public void close( Exception cause ) throws IOException
381     {
382         LOG_CURSOR.debug( "Closing MavibotCursor {}", this );
383         super.close( cause );
384         closeBrowser( browser );
385     }
386 
387 
388     /**
389      * Close the browser
390      */
391     private void closeBrowser( TupleCursor<K, V> browser )
392     {
393         if ( browser != null )
394         {
395             browser.close();
396         }
397     }
398 }