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.avltree;
20  
21  
22  import java.io.IOException;
23  
24  import org.apache.directory.api.ldap.model.constants.Loggers;
25  import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
26  import org.apache.directory.api.ldap.model.cursor.CursorException;
27  import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
28  import org.apache.directory.api.ldap.model.cursor.Tuple;
29  import org.apache.directory.api.ldap.model.exception.LdapException;
30  import org.apache.directory.server.i18n.I18n;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  
35  /**
36   * Cursor over a set of values for the same key which are store in an in
37   * memory AvlTree.  This Cursor is limited to the same key and it's tuples
38   * will always return the same key.
39   *
40   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
41   */
42  public class KeyTupleAvlCursor<K, V> extends AbstractCursor<Tuple<K, V>>
43  {
44      /** A dedicated log for cursors */
45      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
46  
47      /** Speedup for logs */
48      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
49  
50      private final AvlTreeCursor<V> wrapped;
51      private final K key;
52  
53      private Tuple<K, V> returnedTuple = new Tuple<>();
54      private boolean valueAvailable;
55  
56  
57      /**
58       * Creates a Cursor over the tuples of an AvlTree.
59       *
60       * @param avlTree the AvlTree to build a Tuple returning Cursor over
61       * @param key the constant key for which values are returned
62       */
63      public KeyTupleAvlCursor( AvlTree<V> avlTree, K key )
64      {
65          if ( IS_DEBUG )
66          {
67              LOG_CURSOR.debug( "Creating KeyTupleAvlCursor {}", this );
68          }
69  
70          this.key = key;
71          this.wrapped = new AvlTreeCursor<>( avlTree );
72      }
73  
74  
75      private void clearValue()
76      {
77          returnedTuple.setKey( key );
78          returnedTuple.setValue( null );
79          valueAvailable = false;
80      }
81  
82  
83      public boolean available()
84      {
85          return valueAvailable;
86      }
87  
88  
89      public void beforeKey( K key ) throws Exception
90      {
91          throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
92      }
93  
94  
95      public void afterKey( K key ) throws Exception
96      {
97          throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
98      }
99  
100 
101     public void beforeValue( K key, V value ) throws Exception
102     {
103         checkNotClosed();
104         if ( key != null && !key.equals( this.key ) )
105         {
106             throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
107         }
108 
109         wrapped.before( value );
110         clearValue();
111     }
112 
113 
114     public void afterValue( K key, V value ) throws Exception
115     {
116         checkNotClosed();
117         if ( key != null && !key.equals( this.key ) )
118         {
119             throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
120         }
121 
122         wrapped.after( value );
123         clearValue();
124     }
125 
126 
127     /**
128      * Positions this Cursor over the same keys before the value of the
129      * supplied element Tuple.  The supplied element Tuple's key is not
130      * considered at all.
131      *
132      * @param element the valueTuple who's value is used to position this Cursor
133      * @throws CursorException if there are failures to position the Cursor
134      * @throws LdapException if there are failures to position the Cursor
135      */
136     public void before( Tuple<K, V> element ) throws CursorException, LdapException
137     {
138         checkNotClosed();
139         wrapped.before( element.getValue() );
140         clearValue();
141     }
142 
143 
144     /**
145      * {@inheritDoc}
146      */
147     public void after( Tuple<K, V> element ) throws LdapException, CursorException
148     {
149         checkNotClosed();
150         wrapped.after( element.getValue() );
151         clearValue();
152     }
153 
154 
155     /**
156      * {@inheritDoc}
157      */
158     public void beforeFirst() throws LdapException, CursorException
159     {
160         checkNotClosed();
161         wrapped.beforeFirst();
162         clearValue();
163     }
164 
165 
166     /**
167      * {@inheritDoc}
168      */
169     public void afterLast() throws LdapException, CursorException
170     {
171         checkNotClosed();
172         wrapped.afterLast();
173         clearValue();
174     }
175 
176 
177     /**
178      * {@inheritDoc}
179      */
180     public boolean first() throws LdapException, CursorException
181     {
182         beforeFirst();
183         return next();
184     }
185 
186 
187     /**
188      * {@inheritDoc}
189      */
190     public boolean last() throws LdapException, CursorException
191     {
192         afterLast();
193         return previous();
194     }
195 
196 
197     /**
198      * {@inheritDoc}
199      */
200     public boolean previous() throws LdapException, CursorException
201     {
202         checkNotClosed();
203         if ( wrapped.previous() )
204         {
205             returnedTuple.setKey( key );
206             returnedTuple.setValue( wrapped.get() );
207             valueAvailable = true;
208             return true;
209         }
210         else
211         {
212             clearValue();
213             return false;
214         }
215     }
216 
217 
218     /**
219      * {@inheritDoc}
220      */
221     public boolean next() throws LdapException, CursorException
222     {
223         checkNotClosed();
224 
225         if ( wrapped.next() )
226         {
227             returnedTuple.setKey( key );
228             returnedTuple.setValue( wrapped.get() );
229             valueAvailable = true;
230             return true;
231         }
232         else
233         {
234             clearValue();
235             return false;
236         }
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     public Tuple<K, V> get() throws CursorException
244     {
245         checkNotClosed();
246         if ( valueAvailable )
247         {
248             return returnedTuple;
249         }
250 
251         throw new InvalidCursorPositionException();
252     }
253 
254 
255     /**
256      * {@inheritDoc}
257      */
258     @Override
259     public void close() throws IOException
260     {
261         if ( IS_DEBUG )
262         {
263             LOG_CURSOR.debug( "Closing KeyTupleAvlCursor {}", this );
264         }
265 
266         super.close();
267 
268         if ( wrapped != null )
269         {
270             wrapped.close();
271         }
272     }
273 
274 
275     /**
276      * {@inheritDoc}
277      */
278     @Override
279     public void close( Exception cause ) throws IOException
280     {
281         if ( IS_DEBUG )
282         {
283             LOG_CURSOR.debug( "Closing KeyTupleAvlCursor {}", this );
284         }
285 
286         super.close( cause );
287 
288         if ( wrapped != null )
289         {
290             wrapped.close( cause );
291         }
292     }
293 }