1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.avltree;
21
22
23 import java.io.IOException;
24 import java.util.Comparator;
25
26 import org.apache.directory.api.ldap.model.constants.Loggers;
27 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
28 import org.apache.directory.api.ldap.model.cursor.CursorException;
29 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
30 import org.apache.directory.api.ldap.model.cursor.Tuple;
31 import org.apache.directory.api.ldap.model.exception.LdapException;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
36
37
38
39
40
41 public class AvlSingletonOrOrderedSetCursor<K, V> extends AbstractCursor<Tuple<K, SingletonOrOrderedSet<V>>>
42 {
43
44 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
45
46
47 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
48
49
50 private AvlTreeMap<K, V> tree;
51
52
53 private LinkedAvlMapNode<K, V> node;
54
55
56 private Position position = Position.BEFORE_FIRST;
57
58 private Tuple<K, SingletonOrOrderedSet<V>> returnedTuple = new Tuple<>();
59
60
61 public AvlSingletonOrOrderedSetCursor( AvlTreeMap<K, V> tree )
62 {
63 if ( IS_DEBUG )
64 {
65 LOG_CURSOR.debug( "Creating AvlSingletonOrOrderedSetCursor {}", this );
66 }
67
68 this.tree = tree;
69 }
70
71
72 public Comparator<K> getKeyComparator()
73 {
74 return tree.getKeyComparator();
75 }
76
77
78 public Comparator<V> getValuComparator()
79 {
80 return tree.getValueComparator();
81 }
82
83
84
85
86
87 public void after( Tuple<K, SingletonOrOrderedSet<V>> element ) throws LdapException, CursorException
88 {
89 afterKey( element.getKey() );
90 }
91
92
93
94
95
96 public void afterLast() throws LdapException, CursorException
97 {
98 checkNotClosed();
99 node = null;
100 position = Position.AFTER_LAST;
101 }
102
103
104 public boolean available()
105 {
106 return position == Position.ON_NODE;
107 }
108
109
110 public void before( Tuple<K, SingletonOrOrderedSet<V>> element ) throws LdapException, CursorException
111 {
112 beforeKey( element.getKey() );
113 }
114
115
116
117
118
119 public void beforeFirst() throws LdapException, CursorException
120 {
121 checkNotClosed();
122 node = null;
123 position = Position.BEFORE_FIRST;
124 }
125
126
127
128
129
130 public boolean first() throws LdapException, CursorException
131 {
132 checkNotClosed();
133
134 node = tree.getFirst();
135
136 if ( node == null )
137 {
138 position = Position.BEFORE_FIRST;
139 return false;
140 }
141 else
142 {
143 position = Position.ON_NODE;
144 return true;
145 }
146 }
147
148
149
150
151
152 public Tuple<K, SingletonOrOrderedSet<V>> get() throws CursorException
153 {
154 checkNotClosed();
155
156 if ( position == Position.ON_NODE )
157 {
158 returnedTuple.setKey( node.key );
159 returnedTuple.setValue( node.value );
160 return returnedTuple;
161 }
162
163 throw new InvalidCursorPositionException();
164 }
165
166
167
168
169
170 public boolean last() throws LdapException, CursorException
171 {
172 checkNotClosed();
173
174 node = tree.getLast();
175
176 if ( node == null )
177 {
178 position = Position.AFTER_LAST;
179 return false;
180 }
181 else
182 {
183 position = Position.ON_NODE;
184 return true;
185 }
186 }
187
188
189
190
191
192 public boolean next() throws LdapException, CursorException
193 {
194 checkNotClosed();
195
196 switch ( position )
197 {
198 case BEFORE_FIRST:
199 return first();
200
201 case BEFORE_NODE:
202 position = Position.ON_NODE;
203 return true;
204
205 case ON_NODE:
206 case AFTER_NODE:
207 node = node.next;
208
209 if ( node == null )
210 {
211 afterLast();
212
213 return false;
214 }
215 else
216 {
217 position = Position.ON_NODE;
218 return true;
219 }
220
221 case AFTER_LAST:
222 return false;
223
224 default:
225 throw new IllegalStateException( "Unexpected position " + position );
226 }
227 }
228
229
230
231
232
233 public boolean previous() throws LdapException, CursorException
234 {
235 checkNotClosed();
236
237 switch ( position )
238 {
239 case BEFORE_FIRST:
240 return false;
241
242 case BEFORE_NODE:
243 case ON_NODE:
244 node = node.previous;
245 if ( node == null )
246 {
247 beforeFirst();
248 return false;
249 }
250 else
251 {
252 position = Position.ON_NODE;
253 return true;
254 }
255
256 case AFTER_NODE:
257 position = Position.ON_NODE;
258 return true;
259
260 case AFTER_LAST:
261 return last();
262
263 default:
264 throw new IllegalStateException( "Unexpected position " + position );
265 }
266 }
267
268
269
270
271
272 public void afterKey( K key ) throws LdapException, CursorException
273 {
274 checkNotClosed();
275
276 if ( key == null )
277 {
278 afterLast();
279 return;
280 }
281
282 node = tree.findGreater( key );
283
284 if ( node == null )
285 {
286 position = Position.AFTER_LAST;
287 }
288 else
289 {
290
291
292
293 position = Position.BEFORE_NODE;
294 }
295 }
296
297
298 public void afterValue( K key, SingletonOrOrderedSet<V> value ) throws Exception
299 {
300 throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
301 }
302
303
304 public void beforeKey( K key ) throws LdapException, CursorException
305 {
306 checkNotClosed();
307
308 if ( key == null )
309 {
310 beforeFirst();
311 return;
312 }
313
314 node = tree.findLess( key );
315
316 if ( node == null )
317 {
318 position = Position.BEFORE_FIRST;
319 }
320 else
321 {
322
323
324
325 position = Position.AFTER_NODE;
326 }
327 }
328
329
330 public void beforeValue( K key, SingletonOrOrderedSet<V> value ) throws Exception
331 {
332 throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
333 }
334
335
336
337
338
339 @Override
340 public void close() throws IOException
341 {
342 if ( IS_DEBUG )
343 {
344 LOG_CURSOR.debug( "Closing AvlSingletonOrOrderedSetCursor {}", this );
345 }
346
347 super.close();
348 }
349
350
351
352
353
354 @Override
355 public void close( Exception reason ) throws IOException
356 {
357 if ( IS_DEBUG )
358 {
359 LOG_CURSOR.debug( "Closing AvlSingletonOrOrderedSetCursor {}", this );
360 }
361
362 super.close( reason );
363 }
364 }