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.avltree;
21  
22  
23  import java.io.IOException;
24  
25  import org.apache.directory.api.ldap.model.constants.Loggers;
26  import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
27  import org.apache.directory.api.ldap.model.cursor.CursorException;
28  import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
29  import org.apache.directory.api.ldap.model.exception.LdapException;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  
34  /**
35   * A Cursor for an AvlTree.
36   *
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   */
39  public class AvlTreeCursor<E> extends AbstractCursor<E>
40  {
41      /** A dedicated log for cursors */
42      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
43  
44      /** Speedup for logs */
45      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
46  
47      /** The underlying AVL tree */
48      private AvlTree<E> tree;
49  
50      /** The current node */
51      private LinkedAvlNode<E> node;
52  
53      /** The current position of this cursor, relative to the node */
54      private Position position = Position.BEFORE_FIRST;
55  
56  
57      public AvlTreeCursor( AvlTree<E> tree )
58      {
59          if ( IS_DEBUG )
60          {
61              LOG_CURSOR.debug( "Creating AvlTreeCursor {}", this );
62          }
63  
64          this.tree = tree;
65      }
66  
67  
68      /**
69       * {@inheritDoc}
70       */
71      public void after( E element ) throws LdapException, CursorException
72      {
73          checkNotClosed();
74  
75          if ( element == null )
76          {
77              afterLast();
78              return;
79          }
80  
81          node = tree.findGreater( element );
82  
83          if ( node == null )
84          {
85              position = Position.AFTER_LAST;
86          }
87          else
88          {
89              // the cursor should be positioned after the given element
90              // we just fetched the next greater element so the cursor
91              // is positioned before the fetched element
92              position = Position.BEFORE_NODE;
93          }
94      }
95  
96  
97      /**
98       * {@inheritDoc}
99       */
100     public void afterLast() throws LdapException, CursorException
101     {
102         checkNotClosed();
103         node = null;
104         position = Position.AFTER_LAST;
105     }
106 
107 
108     public boolean available()
109     {
110         return position == Position.ON_NODE;
111     }
112 
113 
114     /**
115      * {@inheritDoc}
116      */
117     public void before( E element ) throws LdapException, CursorException
118     {
119         checkNotClosed();
120 
121         if ( element == null )
122         {
123             beforeFirst();
124             return;
125         }
126 
127         node = tree.findLess( element );
128 
129         if ( node == null )
130         {
131             position = Position.BEFORE_FIRST;
132         }
133         else
134         {
135             // the cursor should be positioned before the given element
136             // we just fetched the next less element so the cursor
137             // is positioned after the fetched element
138             position = Position.AFTER_NODE;
139         }
140     }
141 
142 
143     /**
144      * {@inheritDoc}
145      */
146     public void beforeFirst() throws LdapException, CursorException
147     {
148         checkNotClosed();
149         node = null;
150         position = Position.BEFORE_FIRST;
151     }
152 
153 
154     /**
155      * {@inheritDoc}
156      */
157     public boolean first() throws LdapException, CursorException
158     {
159         checkNotClosed();
160 
161         node = tree.getFirst();
162 
163         if ( node == null )
164         {
165             position = Position.BEFORE_FIRST;
166             return false;
167         }
168         else
169         {
170             position = Position.ON_NODE;
171             return true;
172         }
173     }
174 
175 
176     /**
177      * {@inheritDoc}
178      */
179     public E get() throws CursorException
180     {
181         checkNotClosed();
182 
183         if ( position == Position.ON_NODE )
184         {
185             return node.getKey();
186         }
187 
188         throw new InvalidCursorPositionException();
189     }
190 
191 
192     /**
193      * {@inheritDoc}
194      */
195     public boolean last() throws LdapException, CursorException
196     {
197         checkNotClosed();
198 
199         node = tree.getLast();
200 
201         if ( node == null )
202         {
203             position = Position.AFTER_LAST;
204             return false;
205         }
206         else
207         {
208             position = Position.ON_NODE;
209             return true;
210         }
211     }
212 
213 
214     /**
215      * {@inheritDoc}
216      */
217     public boolean next() throws LdapException, CursorException
218     {
219         checkNotClosed();
220 
221         switch ( position )
222         {
223             case BEFORE_FIRST:
224                 return first();
225 
226             case BEFORE_NODE:
227                 position = Position.ON_NODE;
228                 return true;
229 
230             case ON_NODE:
231             case AFTER_NODE:
232                 node = node.next;
233                 if ( node == null )
234                 {
235                     afterLast();
236                     return false;
237                 }
238                 else
239                 {
240                     position = Position.ON_NODE;
241                     return true;
242                 }
243 
244             case AFTER_LAST:
245                 return false;
246 
247             default:
248                 throw new IllegalStateException( "Unexpected position " + position );
249         }
250     }
251 
252 
253     /**
254      * {@inheritDoc}
255      */
256     public boolean previous() throws LdapException, CursorException
257     {
258         checkNotClosed();
259 
260         switch ( position )
261         {
262             case BEFORE_FIRST:
263                 return false;
264 
265             case BEFORE_NODE:
266             case ON_NODE:
267                 node = node.previous;
268                 if ( node == null )
269                 {
270                     beforeFirst();
271                     return false;
272                 }
273                 else
274                 {
275                     position = Position.ON_NODE;
276                     return true;
277                 }
278 
279             case AFTER_NODE:
280                 position = Position.ON_NODE;
281                 return true;
282 
283             case AFTER_LAST:
284                 return last();
285 
286             default:
287                 throw new IllegalStateException( "Unexpected position " + position );
288         }
289     }
290 
291 
292     /**
293      * {@inheritDoc}
294      */
295     @Override
296     public void close() throws IOException
297     {
298         if ( IS_DEBUG )
299         {
300             LOG_CURSOR.debug( "Closing AvlTreeCursor {}", this );
301         }
302 
303         super.close();
304     }
305 
306 
307     /**
308      * {@inheritDoc}
309      */
310     @Override
311     public void close( Exception reason ) throws IOException
312     {
313         if ( IS_DEBUG )
314         {
315             LOG_CURSOR.debug( "Closing AvlTreeCursor {}", this );
316         }
317 
318         super.close( reason );
319     }
320 }