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   */
20  package org.apache.directory.server.core.partition.impl.btree.jdbm;
21  
22  
23  import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
24  import org.apache.directory.server.xdbm.Tuple;
25  import org.apache.directory.server.xdbm.AbstractTupleCursor;
26  import jdbm.helper.TupleBrowser;
27  
28  import java.io.IOException;
29  
30  
31  /**
32   * A cursor for browsing tables with duplicates which returns the container
33   * for values rather than just the value.
34   *
35   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
36   * @version $$Rev$$
37   */
38  public class DupsContainerCursor<K,V> extends AbstractTupleCursor<K, DupsContainer<V>>
39  {
40      private final JdbmTable<K,V> table;
41  
42      private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple();
43      private Tuple<K,DupsContainer<V>> returnedTuple = new Tuple<K,DupsContainer<V>>();
44      private TupleBrowser browser;
45      private boolean valueAvailable;
46      private Boolean forwardDirection;
47  
48  
49      /**
50       * Creates a Cursor over the tuples of a JDBM table.
51       *
52       * @param table the JDBM Table to build a Cursor over
53       * @throws java.io.IOException of there are problems accessing the BTree
54       */
55      public DupsContainerCursor( JdbmTable<K,V> table ) throws IOException
56      {
57          if ( ! table.isDupsEnabled() )
58          {
59              throw new IllegalStateException(
60                  "This cursor can only be used with tables that have duplicate keys enabled." );
61          }
62  
63          this.table = table;
64      }
65  
66  
67      private void clearValue()
68      {
69          returnedTuple.setKey( null );
70          returnedTuple.setValue( null );
71          jdbmTuple.setKey( null );
72          jdbmTuple.setValue( null );
73          valueAvailable = false;
74      }
75  
76  
77      public boolean available()
78      {
79          return valueAvailable;
80      }
81  
82  
83      public void beforeKey( K key ) throws Exception
84      {
85          checkNotClosed( "beforeKey()" );
86          browser = table.getBTree().browse( key );
87          forwardDirection = null;
88          clearValue();
89      }
90  
91  
92      @SuppressWarnings("unchecked")
93      public void afterKey( K key ) throws Exception
94      {
95          browser = table.getBTree().browse( key );
96          forwardDirection = null;
97  
98          /*
99           * While the next value is less than or equal to the element keep
100          * advancing forward to the next item.  If we cannot advance any
101          * further then stop and return.  If we find a value greater than
102          * the element then we stop, backup, and return so subsequent calls
103          * to getNext() will return a value greater than the element.
104          */
105         while ( browser.getNext( jdbmTuple ) )
106         {
107             checkNotClosed( "afterKey()" );
108             K next = ( K ) jdbmTuple.getKey();
109 
110             int nextCompared = table.getKeyComparator().compare( next, key );
111 
112             if ( nextCompared > 0 )
113             {
114                 browser.getPrevious( jdbmTuple );
115 
116                 // switch in direction bug workaround: when a JDBM browser
117                 // switches direction with next then previous as is occuring
118                 // here then two previous moves are needed.
119                 browser.getPrevious( jdbmTuple );
120                 forwardDirection = false;
121                 clearValue();
122                 return;
123             }
124         }
125 
126         clearValue();
127     }
128 
129 
130     public void beforeValue( K key, DupsContainer<V> value ) throws Exception
131     {
132         throw new UnsupportedOperationException( "Value based advances not supported." );
133     }
134 
135 
136     public void afterValue( K key, DupsContainer<V> value ) throws Exception
137     {
138         throw new UnsupportedOperationException( "Value based advances not supported." );
139     }
140 
141 
142     /**
143      * Positions this Cursor before the key of the supplied tuple.
144      *
145      * @param element the tuple who's key is used to position this Cursor
146      * @throws IOException if there are failures to position the Cursor
147      */
148     public void before( Tuple<K,DupsContainer<V>> element ) throws Exception
149     {
150         beforeKey( element.getKey() );
151     }
152 
153 
154     public void after( Tuple<K,DupsContainer<V>> element ) throws Exception
155     {
156         afterKey( element.getKey() );
157     }
158 
159 
160     public void beforeFirst() throws Exception
161     {
162         checkNotClosed( "afterKey()" );
163         browser = table.getBTree().browse();
164         forwardDirection = null;
165         clearValue();
166     }
167 
168 
169     public void afterLast() throws Exception
170     {
171         checkNotClosed( "afterKey()" );
172         browser = table.getBTree().browse( null );
173         forwardDirection = null;
174         clearValue();
175     }
176 
177 
178     public boolean first() throws Exception
179     {
180         beforeFirst();
181         return next();
182     }
183 
184 
185     public boolean last() throws Exception
186     {
187         afterLast();
188         return previous();
189     }
190 
191 
192     @SuppressWarnings("unchecked")
193     public boolean previous() throws Exception
194     {
195         checkNotClosed( "previous()" );
196         if ( browser == null )
197         {
198             afterLast();
199         }
200 
201         boolean advanceSuccess = browser.getPrevious( jdbmTuple );
202 
203         // only want to set this if the advance is a success which means we
204         // are not at front
205         if ( forwardDirection == null && advanceSuccess )
206         {
207             forwardDirection = false;
208         }
209 
210         if ( forwardDirection != null && forwardDirection )
211         {
212             advanceSuccess = browser.getPrevious( jdbmTuple );
213             forwardDirection = false;
214         }
215 
216         if ( advanceSuccess )
217         {
218             returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
219             returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) );
220             return valueAvailable = true;
221         }
222         else
223         {
224             clearValue();
225             return false;
226         }
227     }
228 
229 
230     @SuppressWarnings("unchecked")
231     public boolean next() throws Exception
232     {
233         checkNotClosed( "next()" );
234         if ( browser == null )
235         {
236             beforeFirst();
237         }
238 
239         boolean advanceSuccess = browser.getNext( jdbmTuple );
240 
241         // only want to set this if the advance is a success which means
242         // we are not at end
243         if ( forwardDirection == null && advanceSuccess )
244         {
245             forwardDirection = true;
246         }
247 
248         if ( forwardDirection != null && ! forwardDirection )
249         {
250             advanceSuccess = browser.getNext( jdbmTuple );
251             forwardDirection = true;
252         }
253 
254         if ( advanceSuccess )
255         {
256             returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
257             returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) );
258             return valueAvailable = true;
259         }
260         else
261         {
262             clearValue();
263             return false;
264         }
265     }
266 
267 
268     public Tuple<K,DupsContainer<V>> get() throws Exception
269     {
270         checkNotClosed( "get()" );
271         if ( valueAvailable )
272         {
273             return returnedTuple;
274         }
275 
276         throw new InvalidCursorPositionException();
277     }
278 
279 
280     public boolean isElementReused()
281     {
282         return true;
283     }
284 }