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.jdbm;
20  
21  
22  import java.io.IOException;
23  
24  import jdbm.helper.TupleBrowser;
25  
26  import org.apache.directory.api.ldap.model.constants.Loggers;
27  import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
28  import org.apache.directory.api.ldap.model.cursor.CursorException;
29  import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
30  import org.apache.directory.api.ldap.model.cursor.Tuple;
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.apache.directory.server.i18n.I18n;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  
37  /**
38   * Cursor over the Tuples of a JDBM BTree.  Duplicate keys are not supported
39   * by JDBM natively so you will not see duplicate keys.  For this reason as
40   * well before() and after() positioning only considers the key of the Tuple
41   * arguments provided.
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   */
45  class NoDupsCursor<K, V> extends AbstractCursor<Tuple<K, V>>
46  {
47      /** A dedicated log for cursors */
48      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
49  
50      /** Speedup for logs */
51      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
52  
53      private final JdbmTable<K, V> table;
54  
55      private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple();
56      private Tuple<K, V> returnedTuple = new Tuple<K, V>();
57      private TupleBrowser browser;
58      private boolean valueAvailable;
59  
60  
61      /**
62       * Creates a Cursor over the tuples of a JDBM table.
63       *
64       * @param table the JDBM Table to build a Cursor over
65       * @throws IOException of there are problems accessing the BTree
66       */
67      public NoDupsCursor( JdbmTable<K, V> table )
68      {
69          if ( IS_DEBUG )
70          {
71              LOG_CURSOR.debug( "Creating NoDupsCursor {}", this );
72          }
73  
74          this.table = table;
75      }
76  
77  
78      private void clearValue()
79      {
80          returnedTuple.setKey( null );
81          returnedTuple.setValue( null );
82          jdbmTuple.setKey( null );
83          jdbmTuple.setValue( null );
84          valueAvailable = false;
85      }
86  
87  
88      public boolean available()
89      {
90          return valueAvailable;
91      }
92  
93  
94      public void beforeKey( K key ) throws LdapException, CursorException, IOException
95      {
96          checkNotClosed( "beforeKey()" );
97          browser = table.getBTree().browse( key );
98          clearValue();
99      }
100 
101 
102     @SuppressWarnings("unchecked")
103     public void afterKey( K key ) throws LdapException, CursorException, IOException
104     {
105         browser = table.getBTree().browse( key );
106 
107         /*
108          * While the next value is less than or equal to the element keep
109          * advancing forward to the next item.  If we cannot advance any
110          * further then stop and return.  If we find a value greater than
111          * the element then we stop, backup, and return so subsequent calls
112          * to getNext() will return a value greater than the element.
113          */
114         while ( browser.getNext( jdbmTuple ) )
115         {
116             checkNotClosed( "afterKey()" );
117             K next = ( K ) jdbmTuple.getKey();
118 
119             int nextCompared = table.getKeyComparator().compare( next, key );
120 
121             if ( nextCompared > 0 )
122             {
123                 browser.getPrevious( jdbmTuple );
124                 clearValue();
125                 return;
126             }
127         }
128 
129         clearValue();
130     }
131 
132 
133     public void beforeValue( K key, V value ) throws Exception
134     {
135         throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
136     }
137 
138 
139     public void afterValue( K key, V value ) throws Exception
140     {
141         throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
142     }
143 
144 
145     /**
146      * Positions this Cursor before the key of the supplied tuple.
147      *
148      * @param element the tuple who's key is used to position this Cursor
149      * @throws IOException if there are failures to position the Cursor
150      */
151     public void before( Tuple<K, V> element ) throws LdapException, CursorException, IOException
152     {
153         beforeKey( element.getKey() );
154     }
155 
156 
157     /**
158      * {@inheritDoc}
159      */
160     public void after( Tuple<K, V> element ) throws LdapException, CursorException, IOException
161     {
162         afterKey( element.getKey() );
163     }
164 
165 
166     /**
167      * {@inheritDoc}
168      */
169     public void beforeFirst() throws LdapException, CursorException, IOException
170     {
171         checkNotClosed( "beforeFirst()" );
172         browser = table.getBTree().browse();
173         clearValue();
174     }
175 
176 
177     /**
178      * {@inheritDoc}
179      */
180     public void afterLast() throws LdapException, CursorException, IOException
181     {
182         checkNotClosed( "afterLast()" );
183         browser = table.getBTree().browse( null );
184         clearValue();
185     }
186 
187 
188     /**
189      * {@inheritDoc}
190      */
191     public boolean first() throws LdapException, CursorException, IOException
192     {
193         beforeFirst();
194         return next();
195     }
196 
197 
198     /**
199      * {@inheritDoc}
200      */
201     public boolean last() throws LdapException, CursorException, IOException
202     {
203         afterLast();
204         return previous();
205     }
206 
207 
208     /**
209      * {@inheritDoc}
210      */
211     @SuppressWarnings("unchecked")
212     public boolean previous() throws LdapException, CursorException, IOException
213     {
214         checkNotClosed( "previous()" );
215         if ( browser == null )
216         {
217             afterLast();
218         }
219 
220         if ( browser.getPrevious( jdbmTuple ) )
221         {
222             if ( returnedTuple.getKey() != null && table.getKeyComparator().compare(
223                 ( K ) jdbmTuple.getKey(), returnedTuple.getKey() ) == 0 )
224             {
225                 browser.getPrevious( jdbmTuple );
226             }
227 
228             returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
229             returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
230             return valueAvailable = true;
231         }
232         else
233         {
234             clearValue();
235             return false;
236         }
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     @SuppressWarnings("unchecked")
244     public boolean next() throws LdapException, CursorException, IOException
245     {
246         checkNotClosed( "previous()" );
247 
248         if ( browser == null )
249         {
250             beforeFirst();
251         }
252 
253         if ( browser.getNext( jdbmTuple ) )
254         {
255             if ( returnedTuple.getKey() != null && table.getKeyComparator().compare(
256                 ( K ) jdbmTuple.getKey(), returnedTuple.getKey() ) == 0 )
257             {
258                 browser.getNext( jdbmTuple );
259             }
260 
261             returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
262             returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
263             return valueAvailable = true;
264         }
265         else
266         {
267             clearValue();
268             return false;
269         }
270     }
271 
272 
273     /**
274      * {@inheritDoc}
275      */
276     public Tuple<K, V> get() throws CursorException, IOException
277     {
278         checkNotClosed( "get()" );
279         if ( valueAvailable )
280         {
281             return returnedTuple;
282         }
283 
284         throw new InvalidCursorPositionException();
285     }
286 
287 
288     /**
289      * {@inheritDoc}
290      */
291     @Override
292     public void close()
293     {
294         if ( IS_DEBUG )
295         {
296             LOG_CURSOR.debug( "Closing NoDupsCursor {}", this );
297         }
298 
299         super.close();
300     }
301 
302 
303     /**
304      * {@inheritDoc}
305      */
306     @Override
307     public void close( Exception cause )
308     {
309         if ( IS_DEBUG )
310         {
311             LOG_CURSOR.debug( "Closing NoDupsCursor {}", this );
312         }
313 
314         super.close( cause );
315     }
316 }