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.xdbm.search.impl;
21
22
23 import org.apache.directory.server.xdbm.Index;
24 import org.apache.directory.server.xdbm.IndexEntry;
25 import org.apache.directory.server.xdbm.Store;
26 import org.apache.directory.server.xdbm.AbstractIndexCursor;
27 import org.apache.directory.server.xdbm.IndexCursor;
28 import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
29 import org.apache.directory.server.core.entry.ServerEntry;
30 import org.apache.directory.shared.ldap.entry.Value;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class ApproximateCursor<V> extends AbstractIndexCursor<V, ServerEntry>
46 {
47 private static final String UNSUPPORTED_MSG =
48 "ApproximateCursors only support positioning by element when a user index exists on the asserted attribute.";
49
50
51 private final ApproximateEvaluator approximateEvaluator;
52
53
54 private final IndexCursor<V,ServerEntry> userIdxCursor;
55
56
57 private final IndexCursor<String,ServerEntry> ndnIdxCursor;
58
59
60 private boolean available = false;
61
62
63 public ApproximateCursor( Store<ServerEntry> db, ApproximateEvaluator approximateEvaluator ) throws Exception
64 {
65 this.approximateEvaluator = approximateEvaluator;
66
67 String attribute = approximateEvaluator.getExpression().getAttribute();
68 Value<V> value = approximateEvaluator.getExpression().getValue();
69 if ( db.hasUserIndexOn( attribute ) )
70 {
71
72 Index<V,ServerEntry> index = ( Index<V, ServerEntry> ) db.getUserIndex( attribute );
73 userIdxCursor = index.forwardCursor( value.get() );
74 ndnIdxCursor = null;
75 }
76 else
77 {
78 ndnIdxCursor = db.getNdnIndex().forwardCursor();
79 userIdxCursor = null;
80 }
81 }
82
83
84 public boolean available()
85 {
86 if ( userIdxCursor != null )
87 {
88 return userIdxCursor.available();
89 }
90
91 return available;
92 }
93
94
95 public void beforeValue( Long id, V value ) throws Exception
96 {
97 checkNotClosed( "beforeValue()" );
98 if ( userIdxCursor != null )
99 {
100 userIdxCursor.beforeValue( id, value );
101 }
102 else
103 {
104 throw new UnsupportedOperationException( UNSUPPORTED_MSG );
105 }
106 }
107
108
109 public void afterValue( Long id, V value ) throws Exception
110 {
111 checkNotClosed( "afterValue()" );
112 if ( userIdxCursor != null )
113 {
114 userIdxCursor.afterValue( id, value );
115 }
116 else
117 {
118 throw new UnsupportedOperationException( UNSUPPORTED_MSG );
119 }
120 }
121
122
123 public void before( IndexEntry<V, ServerEntry> element ) throws Exception
124 {
125 checkNotClosed( "before()" );
126 if ( userIdxCursor != null )
127 {
128 userIdxCursor.before( element );
129 }
130 else
131 {
132 throw new UnsupportedOperationException( UNSUPPORTED_MSG );
133 }
134 }
135
136
137 public void after( IndexEntry<V, ServerEntry> element ) throws Exception
138 {
139 checkNotClosed( "after()" );
140 if ( userIdxCursor != null )
141 {
142 userIdxCursor.after( element );
143 }
144 else
145 {
146 throw new UnsupportedOperationException( UNSUPPORTED_MSG );
147 }
148 }
149
150
151 public void beforeFirst() throws Exception
152 {
153 checkNotClosed( "beforeFirst()" );
154 if ( userIdxCursor != null )
155 {
156 userIdxCursor.beforeFirst();
157 }
158 else
159 {
160 ndnIdxCursor.beforeFirst();
161 available = false;
162 }
163 }
164
165
166 public void afterLast() throws Exception
167 {
168 checkNotClosed( "afterLast()" );
169 if ( userIdxCursor != null )
170 {
171 userIdxCursor.afterLast();
172 }
173 else
174 {
175 ndnIdxCursor.afterLast();
176 available = false;
177 }
178 }
179
180
181 public boolean first() throws Exception
182 {
183 beforeFirst();
184 return next();
185 }
186
187
188 public boolean last() throws Exception
189 {
190 afterLast();
191 return previous();
192 }
193
194
195 public boolean previous() throws Exception
196 {
197 if ( userIdxCursor != null )
198 {
199 return userIdxCursor.previous();
200 }
201
202 while( ndnIdxCursor.previous() )
203 {
204 checkNotClosed( "previous()" );
205 IndexEntry<?,ServerEntry> candidate = ndnIdxCursor.get();
206 if ( approximateEvaluator.evaluate( candidate ) )
207 {
208 return available = true;
209 }
210 }
211
212 return available = false;
213 }
214
215
216 public boolean next() throws Exception
217 {
218 if ( userIdxCursor != null )
219 {
220 return userIdxCursor.next();
221 }
222
223 while( ndnIdxCursor.next() )
224 {
225 checkNotClosed( "next()" );
226 IndexEntry<?,ServerEntry> candidate = ndnIdxCursor.get();
227 if ( approximateEvaluator.evaluate( candidate ) )
228 {
229 return available = true;
230 }
231 }
232
233 return available = false;
234 }
235
236
237 @SuppressWarnings("unchecked")
238 public IndexEntry<V, ServerEntry> get() throws Exception
239 {
240 checkNotClosed( "get()" );
241 if ( userIdxCursor != null )
242 {
243 return userIdxCursor.get();
244 }
245
246 if ( available )
247 {
248 return ( IndexEntry<V, ServerEntry> ) ndnIdxCursor.get();
249 }
250
251 throw new InvalidCursorPositionException( "Cursor has not been positioned yet." );
252 }
253
254
255 public boolean isElementReused()
256 {
257 if ( userIdxCursor != null )
258 {
259 return userIdxCursor.isElementReused();
260 }
261
262 return ndnIdxCursor.isElementReused();
263 }
264
265
266 public void close() throws Exception
267 {
268 super.close();
269
270 if ( userIdxCursor != null )
271 {
272 userIdxCursor.close();
273 }
274 else
275 {
276 ndnIdxCursor.close();
277 }
278 }
279 }