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.Comparator;
24  
25  import org.apache.directory.api.i18n.I18n;
26  import org.apache.directory.api.ldap.model.constants.Loggers;
27  import org.apache.directory.api.ldap.model.exception.LdapException;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  
32  /**
33   * A Cursor over a single element.
34   *
35   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
36   * @param <E> The type of element on which this cursor will iterate
37   */
38  public class SingletonCursor<E> extends AbstractCursor<E>
39  {
40      /** A dedicated log for cursors */
41      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
42  
43      /** Speedup for logs */
44      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
45  
46      /** A flag to tell if the cursor is set before the first element */
47      private boolean beforeFirst = true;
48  
49      /** A flag to tell if the cursor is set after the last element */
50      private boolean afterLast;
51  
52      /** A flag to tell if the cursor is on the element */
53      private boolean onSingleton;
54  
55      /** The comparator used for this cursor. */
56      private final Comparator<E> comparator;
57  
58      /** The unique element stored in the cursor */
59      private final E singleton;
60  
61  
62      /**
63       * Creates a new instance of SingletonCursor.
64       *
65       * @param singleton The unique element to store into this cursor
66       */
67      public SingletonCursor( E singleton )
68      {
69          this( singleton, null );
70      }
71  
72  
73      /**
74       * Creates a new instance of SingletonCursor, with its associated
75       * comparator
76       *
77       * @param singleton The unique element to store into this cursor
78       * @param comparator The associated comparator
79       */
80      public SingletonCursor( E singleton, Comparator<E> comparator )
81      {
82          if ( IS_DEBUG )
83          {
84              LOG_CURSOR.debug( "Creating SingletonCursor {}", this );
85          }
86  
87          this.singleton = singleton;
88          this.comparator = comparator;
89      }
90  
91  
92      /**
93       * {@inheritDoc}
94       */
95      @Override
96      public boolean available()
97      {
98          return onSingleton;
99      }
100 
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     public void before( E element ) throws LdapException, CursorException
107     {
108         checkNotClosed( "before()" );
109 
110         if ( comparator == null )
111         {
112             throw new UnsupportedOperationException( I18n.err( I18n.ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE ) );
113         }
114 
115         int comparison = comparator.compare( singleton, element );
116 
117         if ( comparison < 0 )
118         {
119             first();
120         }
121         else
122         {
123             beforeFirst();
124         }
125     }
126 
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public void after( E element ) throws LdapException, CursorException
133     {
134         checkNotClosed( "after()" );
135 
136         if ( comparator == null )
137         {
138             throw new UnsupportedOperationException( I18n.err( I18n.ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER ) );
139         }
140 
141         int comparison = comparator.compare( singleton, element );
142 
143         if ( comparison > 0 )
144         {
145             first();
146         }
147         else
148         {
149             afterLast();
150         }
151     }
152 
153 
154     /**
155      * {@inheritDoc}
156      */
157     @Override
158     public void beforeFirst() throws LdapException, CursorException
159     {
160         checkNotClosed( "beforeFirst" );
161         beforeFirst = true;
162         afterLast = false;
163         onSingleton = false;
164     }
165 
166 
167     /**
168      * {@inheritDoc}
169      */
170     @Override
171     public void afterLast() throws LdapException, CursorException
172     {
173         checkNotClosed( "afterLast" );
174         beforeFirst = false;
175         afterLast = true;
176         onSingleton = false;
177     }
178 
179 
180     /**
181      * {@inheritDoc}
182      */
183     @Override
184     public boolean first() throws LdapException, CursorException
185     {
186         checkNotClosed( "first" );
187         beforeFirst = false;
188         onSingleton = true;
189         afterLast = false;
190 
191         return true;
192     }
193 
194 
195     /**
196      * {@inheritDoc}
197      */
198     @Override
199     public boolean last() throws LdapException, CursorException
200     {
201         checkNotClosed( "last" );
202         beforeFirst = false;
203         onSingleton = true;
204         afterLast = false;
205 
206         return true;
207     }
208 
209 
210     /**
211      * {@inheritDoc}
212      */
213     @Override
214     public boolean isFirst()
215     {
216         return onSingleton;
217     }
218 
219 
220     /**
221      * {@inheritDoc}
222      */
223     @Override
224     public boolean isLast()
225     {
226         return onSingleton;
227     }
228 
229 
230     /**
231      * {@inheritDoc}
232      */
233     @Override
234     public boolean isAfterLast()
235     {
236         return afterLast;
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     @Override
244     public boolean isBeforeFirst()
245     {
246         return beforeFirst;
247     }
248 
249 
250     /**
251      * {@inheritDoc}
252      */
253     @Override
254     public boolean previous() throws LdapException, CursorException
255     {
256         checkNotClosed( "previous" );
257 
258         if ( beforeFirst )
259         {
260             return false;
261         }
262 
263         if ( afterLast )
264         {
265             beforeFirst = false;
266             onSingleton = true;
267             afterLast = false;
268 
269             return true;
270         }
271 
272         // must be on the singleton
273         beforeFirst = true;
274         onSingleton = false;
275         afterLast = false;
276 
277         return false;
278     }
279 
280 
281     /**
282      * {@inheritDoc}
283      */
284     @Override
285     public boolean next() throws LdapException, CursorException
286     {
287         checkNotClosed( "next" );
288 
289         if ( beforeFirst )
290         {
291             beforeFirst = false;
292             onSingleton = true;
293             afterLast = false;
294 
295             return true;
296         }
297 
298         if ( afterLast )
299         {
300             return false;
301         }
302 
303         // must be on the singleton
304         beforeFirst = false;
305         onSingleton = false;
306         afterLast = true;
307 
308         return false;
309     }
310 
311 
312     /**
313      * {@inheritDoc}
314      */
315     @Override
316     public E get() throws CursorException
317     {
318         checkNotClosed( "get" );
319 
320         if ( onSingleton )
321         {
322             return singleton;
323         }
324 
325         if ( beforeFirst )
326         {
327             throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST ) );
328         }
329         else
330         {
331             throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST ) );
332         }
333     }
334 
335 
336     /**
337      * {@inheritDoc}
338      */
339     @Override
340     public void close() throws IOException
341     {
342         if ( IS_DEBUG )
343         {
344             LOG_CURSOR.debug( "Closing SingletonCursor {}", this );
345         }
346 
347         super.close();
348     }
349 
350 
351     /**
352      * {@inheritDoc}
353      */
354     @Override
355     public void close( Exception cause ) throws IOException
356     {
357         if ( IS_DEBUG )
358         {
359             LOG_CURSOR.debug( "Closing SingletonCursor {}", this );
360         }
361 
362         super.close( cause );
363     }
364 }