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