1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.directory.server.core.partition.impl.btree.jdbm;
20
21
22 import java.io.IOException;
23
24 import jdbm.helper.TupleBrowser;
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.apache.directory.server.i18n.I18n;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39
40
41
42
43
44
45 class NoDupsCursor<K, V> extends AbstractCursor<Tuple<K, V>>
46 {
47
48 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
49
50
51 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
52
53 private final JdbmTable<K, V> table;
54
55 private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple();
56 private Tuple<K, V> returnedTuple = new Tuple<K, V>();
57 private TupleBrowser browser;
58 private boolean valueAvailable;
59
60
61
62
63
64
65
66
67 public NoDupsCursor( JdbmTable<K, V> table )
68 {
69 if ( IS_DEBUG )
70 {
71 LOG_CURSOR.debug( "Creating NoDupsCursor {}", this );
72 }
73
74 this.table = table;
75 }
76
77
78 private void clearValue()
79 {
80 returnedTuple.setKey( null );
81 returnedTuple.setValue( null );
82 jdbmTuple.setKey( null );
83 jdbmTuple.setValue( null );
84 valueAvailable = false;
85 }
86
87
88 public boolean available()
89 {
90 return valueAvailable;
91 }
92
93
94 public void beforeKey( K key ) throws LdapException, CursorException, IOException
95 {
96 checkNotClosed( "beforeKey()" );
97 browser = table.getBTree().browse( key );
98 clearValue();
99 }
100
101
102 @SuppressWarnings("unchecked")
103 public void afterKey( K key ) throws LdapException, CursorException, IOException
104 {
105 browser = table.getBTree().browse( key );
106
107
108
109
110
111
112
113
114 while ( browser.getNext( jdbmTuple ) )
115 {
116 checkNotClosed( "afterKey()" );
117 K next = ( K ) jdbmTuple.getKey();
118
119 int nextCompared = table.getKeyComparator().compare( next, key );
120
121 if ( nextCompared > 0 )
122 {
123 browser.getPrevious( jdbmTuple );
124 clearValue();
125 return;
126 }
127 }
128
129 clearValue();
130 }
131
132
133 public void beforeValue( K key, V value ) throws Exception
134 {
135 throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
136 }
137
138
139 public void afterValue( K key, V value ) throws Exception
140 {
141 throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
142 }
143
144
145
146
147
148
149
150
151 public void before( Tuple<K, V> element ) throws LdapException, CursorException, IOException
152 {
153 beforeKey( element.getKey() );
154 }
155
156
157
158
159
160 public void after( Tuple<K, V> element ) throws LdapException, CursorException, IOException
161 {
162 afterKey( element.getKey() );
163 }
164
165
166
167
168
169 public void beforeFirst() throws LdapException, CursorException, IOException
170 {
171 checkNotClosed( "beforeFirst()" );
172 browser = table.getBTree().browse();
173 clearValue();
174 }
175
176
177
178
179
180 public void afterLast() throws LdapException, CursorException, IOException
181 {
182 checkNotClosed( "afterLast()" );
183 browser = table.getBTree().browse( null );
184 clearValue();
185 }
186
187
188
189
190
191 public boolean first() throws LdapException, CursorException, IOException
192 {
193 beforeFirst();
194 return next();
195 }
196
197
198
199
200
201 public boolean last() throws LdapException, CursorException, IOException
202 {
203 afterLast();
204 return previous();
205 }
206
207
208
209
210
211 @SuppressWarnings("unchecked")
212 public boolean previous() throws LdapException, CursorException, IOException
213 {
214 checkNotClosed( "previous()" );
215 if ( browser == null )
216 {
217 afterLast();
218 }
219
220 if ( browser.getPrevious( jdbmTuple ) )
221 {
222 if ( returnedTuple.getKey() != null && table.getKeyComparator().compare(
223 ( K ) jdbmTuple.getKey(), returnedTuple.getKey() ) == 0 )
224 {
225 browser.getPrevious( jdbmTuple );
226 }
227
228 returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
229 returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
230 return valueAvailable = true;
231 }
232 else
233 {
234 clearValue();
235 return false;
236 }
237 }
238
239
240
241
242
243 @SuppressWarnings("unchecked")
244 public boolean next() throws LdapException, CursorException, IOException
245 {
246 checkNotClosed( "previous()" );
247
248 if ( browser == null )
249 {
250 beforeFirst();
251 }
252
253 if ( browser.getNext( jdbmTuple ) )
254 {
255 if ( returnedTuple.getKey() != null && table.getKeyComparator().compare(
256 ( K ) jdbmTuple.getKey(), returnedTuple.getKey() ) == 0 )
257 {
258 browser.getNext( jdbmTuple );
259 }
260
261 returnedTuple.setKey( ( K ) jdbmTuple.getKey() );
262 returnedTuple.setValue( ( V ) jdbmTuple.getValue() );
263 return valueAvailable = true;
264 }
265 else
266 {
267 clearValue();
268 return false;
269 }
270 }
271
272
273
274
275
276 public Tuple<K, V> get() throws CursorException, IOException
277 {
278 checkNotClosed( "get()" );
279 if ( valueAvailable )
280 {
281 return returnedTuple;
282 }
283
284 throw new InvalidCursorPositionException();
285 }
286
287
288
289
290
291 @Override
292 public void close()
293 {
294 if ( IS_DEBUG )
295 {
296 LOG_CURSOR.debug( "Closing NoDupsCursor {}", this );
297 }
298
299 super.close();
300 }
301
302
303
304
305
306 @Override
307 public void close( Exception cause )
308 {
309 if ( IS_DEBUG )
310 {
311 LOG_CURSOR.debug( "Closing NoDupsCursor {}", this );
312 }
313
314 super.close( cause );
315 }
316 }