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