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.api.ldap.model.cursor;
20  
21  
22  import java.io.IOException;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.Set;
26  
27  import org.apache.directory.api.i18n.I18n;
28  import org.apache.directory.api.ldap.model.constants.Loggers;
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 simple implementation of a Cursor on a {@link Set}.  Optionally, the
36   * Cursor may be limited to a specific range within the list.
37   *
38   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
39   * @param <E> The element on which this cursor will iterate
40   */
41  public class SetCursor<E> extends AbstractCursor<E>
42  {
43      /** A dedicated log for cursors */
44      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
45  
46      /** Speedup for logs */
47      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
48  
49      /** The inner Set */
50      private final E[] set;
51  
52      /** The associated comparator */
53      private final Comparator<E> comparator;
54  
55      /** The current position in the list */
56      private int index = -1;
57  
58      /** A limit to what we can print */
59      private static final int MAX_PRINTED_ELEMENT = 100;
60  
61  
62      /**
63       * Creates a new SetCursor.
64       *
65       * As with all Cursors, this SetCursor requires a successful return from
66       * advance operations (next() or previous()) to properly return values
67       * using the get() operation.
68       *
69       * @param comparator an optional comparator to use for ordering
70       * @param set the Set this StCursor operates on
71       */
72      @SuppressWarnings("unchecked")
73      public SetCursor( Comparator<E> comparator, Set<E> set )
74      {
75          if ( set == null )
76          {
77              set = Collections.EMPTY_SET;
78          }
79  
80          if ( IS_DEBUG )
81          {
82              LOG_CURSOR.debug( "Creating SetCursor {}", this );
83          }
84  
85          this.comparator = comparator;
86          this.set = ( E[] ) set.toArray();
87      }
88  
89  
90      /**
91       * Creates a new SetCursor
92       *
93       * As with all Cursors, this SetCursor requires a successful return from
94       * advance operations (next() or previous()) to properly return values
95       * using the get() operation.
96       *
97       * @param set the Set this SetCursor operates on
98       */
99      public SetCursor( Set<E> set )
100     {
101         this( null, set );
102     }
103 
104 
105     /**
106      * Creates a new SetCursor without any elements.
107      */
108     @SuppressWarnings("unchecked")
109     public SetCursor()
110     {
111         this( null, Collections.EMPTY_SET );
112     }
113 
114 
115     /**
116      * Creates a new SetCursor without any elements. We also provide 
117      * a comparator.
118      * 
119      * @param comparator The comparator to use for the &lt;E&gt; elements
120      */
121     @SuppressWarnings("unchecked")
122     public SetCursor( Comparator<E> comparator )
123     {
124         this( comparator, Collections.EMPTY_SET );
125     }
126 
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public boolean available()
133     {
134         return ( index >= 0 ) && ( index < set.length );
135     }
136 
137 
138     /**
139      * {@inheritDoc}
140      */
141     @Override
142     public void before( E element ) throws LdapException, CursorException
143     {
144         checkNotClosed( "before()" );
145 
146         if ( comparator == null )
147         {
148             throw new IllegalStateException();
149         }
150 
151         // handle some special cases
152         if ( set.length == 0 )
153         {
154             return;
155         }
156         else if ( set.length == 1 )
157         {
158             if ( comparator.compare( element, set[0] ) <= 0 )
159             {
160                 beforeFirst();
161             }
162             else
163             {
164                 afterLast();
165             }
166         }
167 
168         throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
169     }
170 
171 
172     /**
173      * {@inheritDoc}
174      */
175     @Override
176     public void after( E element ) throws LdapException, CursorException
177     {
178         checkNotClosed( "after()" );
179 
180         if ( comparator == null )
181         {
182             throw new IllegalStateException();
183         }
184 
185         // handle some special cases
186         if ( set.length == 0 )
187         {
188             return;
189         }
190         else if ( set.length == 1 )
191         {
192             if ( comparator.compare( element, set[0] ) >= 0 )
193             {
194                 afterLast();
195             }
196             else
197             {
198                 beforeFirst();
199             }
200         }
201 
202         throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
203     }
204 
205 
206     /**
207      * {@inheritDoc}
208      */
209     @Override
210     public void beforeFirst() throws LdapException, CursorException
211     {
212         checkNotClosed( "beforeFirst()" );
213         this.index = -1;
214     }
215 
216 
217     /**
218      * {@inheritDoc}
219      */
220     @Override
221     public void afterLast() throws LdapException, CursorException
222     {
223         checkNotClosed( "afterLast()" );
224         this.index = set.length;
225     }
226 
227 
228     /**
229      * {@inheritDoc}
230      */
231     @Override
232     public boolean first() throws LdapException, CursorException
233     {
234         checkNotClosed( "first()" );
235 
236         if ( set.length > 0 )
237         {
238             index = 0;
239 
240             return true;
241         }
242 
243         return false;
244     }
245 
246 
247     /**
248      * {@inheritDoc}
249      */
250     @Override
251     public boolean last() throws LdapException, CursorException
252     {
253         checkNotClosed( "last()" );
254 
255         if ( set.length > 0 )
256         {
257             index = set.length - 1;
258 
259             return true;
260         }
261 
262         return false;
263     }
264 
265 
266     /**
267      * {@inheritDoc}
268      */
269     @Override
270     public boolean isFirst()
271     {
272         return ( set.length > 0 ) && ( index == 0 );
273     }
274 
275 
276     /**
277      * {@inheritDoc}
278      */
279     @Override
280     public boolean isLast()
281     {
282         return ( set.length > 0 ) && ( index == set.length - 1 );
283     }
284 
285 
286     /**
287      * {@inheritDoc}
288      */
289     @Override
290     public boolean isAfterLast()
291     {
292         return index == set.length;
293     }
294 
295 
296     /**
297      * {@inheritDoc}
298      */
299     @Override
300     public boolean isBeforeFirst()
301     {
302         return index == -1;
303     }
304 
305 
306     /**
307      * {@inheritDoc}
308      */
309     @Override
310     public boolean previous() throws LdapException, CursorException
311     {
312         checkNotClosed( "previous()" );
313 
314         // if parked at -1 we cannot go backwards
315         if ( index == -1 )
316         {
317             return false;
318         }
319 
320         // if the index moved back is still greater than or eq to start then OK
321         if ( index - 1 >= 0 )
322         {
323             index--;
324 
325             return true;
326         }
327 
328         // if the index currently less than or equal to start we need to park it at -1 and return false
329         if ( index <= 0 )
330         {
331             index = -1;
332 
333             return false;
334         }
335 
336         if ( set.length <= 0 )
337         {
338             index = -1;
339         }
340 
341         return false;
342     }
343 
344 
345     /**
346      * {@inheritDoc}
347      */
348     @Override
349     public boolean next() throws LdapException, CursorException
350     {
351         checkNotClosed( "next()" );
352 
353         // if parked at -1 we advance to the start index and return true
354         if ( ( set.length > 0 ) && ( index == -1 ) )
355         {
356             index = 0;
357 
358             return true;
359         }
360 
361         // if the index plus one is less than the end then increment and return true
362         if ( ( set.length > 0 ) && ( index + 1 < set.length ) )
363         {
364             index++;
365 
366             return true;
367         }
368 
369         // if the index plus one is equal to the end then increment and return false
370         if ( ( set.length > 0 ) && ( index + 1 == set.length ) )
371         {
372             index++;
373 
374             return false;
375         }
376 
377         if ( set.length <= 0 )
378         {
379             index = set.length;
380         }
381 
382         return false;
383     }
384 
385 
386     /**
387      * {@inheritDoc}
388      */
389     @Override
390     public E get() throws CursorException
391     {
392         checkNotClosed( "get()" );
393 
394         if ( ( index < 0 ) || ( index >= set.length ) )
395         {
396             throw new CursorException( I18n.err( I18n.ERR_02009_CURSOR_NOT_POSITIONED ) );
397         }
398 
399         return set[index];
400     }
401 
402 
403     /**
404      * {@inheritDoc}
405      */
406     @Override
407     public void close() throws IOException
408     {
409         if ( IS_DEBUG )
410         {
411             LOG_CURSOR.debug( "Closing ListCursor {}", this );
412         }
413 
414         super.close();
415     }
416 
417 
418     /**
419      * {@inheritDoc}
420      */
421     @Override
422     public void close( Exception cause ) throws IOException
423     {
424         if ( IS_DEBUG )
425         {
426             LOG_CURSOR.debug( "Closing ListCursor {}", this );
427         }
428 
429         super.close( cause );
430     }
431 
432 
433     /**
434      * @see Object#toString()
435      */
436     @Override
437     public String toString( String tabs )
438     {
439         StringBuilder sb = new StringBuilder();
440 
441         sb.append( tabs ).append( "SetCursor :\n" );
442         sb.append( tabs ).append( "    Index : " ).append( index ).append( "\n" );
443 
444         if ( ( set != null ) && ( set.length > 0 ) )
445         {
446             sb.append( tabs ).append( "    Size : " ).append( set.length ).append( "\n" );
447 
448             // Don't print more than 100 elements...
449             int counter = 0;
450 
451             for ( E e : set )
452             {
453                 sb.append( tabs ).append( "    " ).append( e ).append( "\n" );
454                 counter++;
455 
456                 if ( counter == MAX_PRINTED_ELEMENT )
457                 {
458                     break;
459                 }
460             }
461         }
462 
463         return sb.toString();
464     }
465 
466 
467     /**
468      * @see Object#toString()
469      */
470     @Override
471     public String toString()
472     {
473         return toString( "" );
474     }
475 }