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