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