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.filtering;
21
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.directory.server.core.cursor.ClosureMonitor;
29 import org.apache.directory.server.core.cursor.Cursor;
30 import org.apache.directory.server.core.cursor.CursorIterator;
31 import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
32 import org.apache.directory.server.core.entry.ClonedServerEntry;
33 import org.apache.directory.server.core.entry.ServerEntry;
34 import org.apache.directory.server.core.interceptor.context.SearchingOperationContext;
35 import org.apache.directory.shared.ldap.exception.OperationAbandonedException;
36 import org.apache.directory.shared.ldap.schema.AttributeType;
37 import org.apache.directory.shared.ldap.schema.AttributeTypeOptions;
38 import org.apache.directory.shared.ldap.schema.UsageEnum;
39
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43
44
45
46
47
48
49
50
51
52
53 public class BaseEntryFilteringCursor implements EntryFilteringCursor
54 {
55
56 private static final Logger log = LoggerFactory.getLogger( BaseEntryFilteringCursor.class );
57
58
59 private final Cursor<ServerEntry> wrapped;
60
61
62 private final SearchingOperationContext operationContext;
63
64
65 private final List<EntryFilter> filters;
66
67
68 private ClonedServerEntry prefetched;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public BaseEntryFilteringCursor( Cursor<ServerEntry> wrapped,
86 SearchingOperationContext operationContext, EntryFilter filter )
87 {
88 this( wrapped, operationContext, Collections.singletonList( filter ) );
89 }
90
91
92
93
94
95
96
97
98
99
100
101 public BaseEntryFilteringCursor( Cursor<ServerEntry> wrapped, SearchingOperationContext operationContext )
102 {
103 this.wrapped = wrapped;
104 this.operationContext = operationContext;
105 this.filters = new ArrayList<EntryFilter>();
106 }
107
108
109
110
111
112
113
114
115
116
117
118 public BaseEntryFilteringCursor( Cursor<ServerEntry> wrapped,
119 SearchingOperationContext operationContext, List<EntryFilter> filters )
120 {
121 this.wrapped = wrapped;
122 this.operationContext = operationContext;
123 this.filters = new ArrayList<EntryFilter>();
124 this.filters.addAll( filters );
125 }
126
127
128
129
130
131
132
133
134
135
136 public boolean isAbandoned()
137 {
138 return getOperationContext().isAbandoned();
139 }
140
141
142
143
144
145 public void setAbandoned( boolean abandoned )
146 {
147 getOperationContext().setAbandoned( abandoned );
148
149 if ( abandoned )
150 {
151 log.info( "Cursor has been abandoned." );
152 }
153 }
154
155
156
157
158
159 public boolean addEntryFilter( EntryFilter filter )
160 {
161 return filters.add( filter );
162 }
163
164
165
166
167
168 public boolean removeEntryFilter( EntryFilter filter )
169 {
170 return filters.remove( filter );
171 }
172
173
174
175
176
177 public List<EntryFilter> getEntryFilters()
178 {
179 return Collections.unmodifiableList( filters );
180 }
181
182
183
184
185
186 public SearchingOperationContext getOperationContext()
187 {
188 return operationContext;
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203 public void after( ClonedServerEntry element ) throws Exception
204 {
205 throw new UnsupportedOperationException();
206 }
207
208
209
210
211
212
213
214
215 public void afterLast() throws Exception
216 {
217 wrapped.afterLast();
218 prefetched = null;
219 }
220
221
222
223
224
225
226
227
228 public boolean available()
229 {
230 return prefetched != null;
231 }
232
233
234
235
236
237
238
239
240 public void before( ClonedServerEntry element ) throws Exception
241 {
242 throw new UnsupportedOperationException();
243 }
244
245
246
247
248
249
250
251
252 public void beforeFirst() throws Exception
253 {
254 wrapped.beforeFirst();
255 prefetched = null;
256 }
257
258
259
260
261
262
263
264
265 public void close() throws Exception
266 {
267 wrapped.close();
268 prefetched = null;
269 }
270
271
272
273
274
275
276
277
278 public void close( Exception reason ) throws Exception
279 {
280 wrapped.close( reason );
281 prefetched = null;
282 }
283
284
285 public final void setClosureMonitor( ClosureMonitor monitor )
286 {
287 wrapped.setClosureMonitor( monitor );
288 }
289
290
291
292
293
294
295
296
297 public boolean first() throws Exception
298 {
299 if ( getOperationContext().isAbandoned() )
300 {
301 log.info( "Cursor has been abandoned." );
302 close();
303 throw new OperationAbandonedException();
304 }
305
306 beforeFirst();
307 return next();
308 }
309
310
311
312
313
314
315
316
317 public ClonedServerEntry get() throws Exception
318 {
319 if ( available() )
320 {
321 return prefetched;
322 }
323
324 throw new InvalidCursorPositionException();
325 }
326
327
328
329
330
331
332
333
334 public boolean isClosed() throws Exception
335 {
336 return wrapped.isClosed();
337 }
338
339
340
341
342
343
344
345
346 public boolean isElementReused()
347 {
348 return true;
349 }
350
351
352
353
354
355
356
357
358 public boolean last() throws Exception
359 {
360 if ( getOperationContext().isAbandoned() )
361 {
362 log.info( "Cursor has been abandoned." );
363 close();
364 throw new OperationAbandonedException();
365 }
366
367 afterLast();
368 return previous();
369 }
370
371
372 private void filterContents( ClonedServerEntry entry ) throws Exception
373 {
374 boolean returnAll = getOperationContext().getReturningAttributes() == null ||
375 ( getOperationContext().isAllOperationalAttributes() && getOperationContext().isAllUserAttributes() );
376
377 if ( returnAll )
378 {
379 return;
380 }
381
382 if ( getOperationContext().isAllUserAttributes() )
383 {
384 for ( AttributeType at : entry.getOriginalEntry().getAttributeTypes() )
385 {
386 boolean isNotRequested = true;
387
388 for ( AttributeTypeOptions attrOptions:getOperationContext().getReturningAttributes() )
389 {
390 if ( attrOptions.getAttributeType().equals( at ) || attrOptions.getAttributeType().isAncestorOf( at ) )
391 {
392 isNotRequested = false;
393 break;
394 }
395 }
396
397 boolean isNotUserAttribute = at.getUsage() != UsageEnum.USER_APPLICATIONS;
398
399 if ( isNotRequested && isNotUserAttribute )
400 {
401 entry.removeAttributes( at );
402 }
403 }
404
405 return;
406 }
407
408 if ( getOperationContext().isAllOperationalAttributes() )
409 {
410 for ( AttributeType at : entry.getOriginalEntry().getAttributeTypes() )
411 {
412 boolean isNotRequested = true;
413
414 for ( AttributeTypeOptions attrOptions:getOperationContext().getReturningAttributes() )
415 {
416 if ( attrOptions.getAttributeType().equals( at ) || attrOptions.getAttributeType().isAncestorOf( at ) )
417 {
418 isNotRequested = false;
419 break;
420 }
421 }
422
423 boolean isUserAttribute = at.getUsage() == UsageEnum.USER_APPLICATIONS;
424
425 if ( isNotRequested && isUserAttribute )
426 {
427 entry.removeAttributes( at );
428 }
429 }
430
431 return;
432 }
433
434 if ( getOperationContext().isNoAttributes() )
435 {
436 for ( AttributeType at : entry.getOriginalEntry().getAttributeTypes() )
437 {
438 boolean isNotRequested = true;
439
440 for ( AttributeTypeOptions attrOptions:getOperationContext().getReturningAttributes() )
441 {
442 if ( attrOptions.getAttributeType().equals( at ) || attrOptions.getAttributeType().isAncestorOf( at ) )
443 {
444 isNotRequested = false;
445 break;
446 }
447 }
448
449 if ( isNotRequested )
450 {
451 entry.removeAttributes( at );
452 }
453 }
454
455 return;
456 }
457
458 if ( getOperationContext().getReturningAttributes() != null )
459 {
460 for ( AttributeType at : entry.getOriginalEntry().getAttributeTypes() )
461 {
462 boolean isNotRequested = true;
463
464 for ( AttributeTypeOptions attrOptions:getOperationContext().getReturningAttributes() )
465 {
466 if ( attrOptions.getAttributeType().equals( at ) || attrOptions.getAttributeType().isAncestorOf( at ) )
467 {
468 isNotRequested = false;
469 break;
470 }
471 }
472
473 if ( isNotRequested )
474 {
475 entry.removeAttributes( at );
476 }
477 }
478 }
479 }
480
481
482
483
484
485
486
487
488 public boolean next() throws Exception
489 {
490 if ( getOperationContext().isAbandoned() )
491 {
492 log.info( "Cursor has been abandoned." );
493 close();
494 throw new OperationAbandonedException();
495 }
496
497 ClonedServerEntry tempResult = null;
498 outer: while ( wrapped.next() )
499 {
500 boolean accepted = true;
501
502 ServerEntry tempEntry = wrapped.get();
503 if ( tempEntry instanceof ClonedServerEntry )
504 {
505 tempResult = ( ClonedServerEntry ) tempEntry;
506 }
507 else
508 {
509 tempResult = new ClonedServerEntry( tempEntry );
510 }
511
512
513
514
515
516
517
518
519
520 if ( filters.isEmpty() )
521 {
522 prefetched = tempResult;
523 filterContents( prefetched );
524 return true;
525 }
526
527 if ( filters.size() == 1 )
528 {
529 if ( filters.get( 0 ).accept( getOperationContext(), tempResult ) )
530 {
531 prefetched = tempResult;
532 filterContents( prefetched );
533 return true;
534 }
535 }
536
537
538
539 for ( EntryFilter filter : filters )
540 {
541
542 if ( ! ( accepted &= filter.accept( getOperationContext(), tempResult ) ) )
543 {
544 continue outer;
545 }
546 }
547
548
549
550
551 prefetched = tempResult;
552 filterContents( prefetched );
553 return true;
554 }
555
556 prefetched = null;
557 return false;
558 }
559
560
561
562
563
564
565
566
567 public boolean previous() throws Exception
568 {
569 if ( getOperationContext().isAbandoned() )
570 {
571 log.info( "Cursor has been abandoned." );
572 close();
573 throw new OperationAbandonedException();
574 }
575
576 ClonedServerEntry tempResult = null;
577 outer: while ( wrapped.previous() )
578 {
579 boolean accepted = true;
580 tempResult = new ClonedServerEntry( wrapped.get() );
581
582
583
584
585
586
587
588
589
590 if ( filters.isEmpty() )
591 {
592 prefetched = tempResult;
593 filterContents( prefetched );
594 return true;
595 }
596
597 if ( filters.size() == 1 )
598 {
599 if ( filters.get( 0 ).accept( getOperationContext(), tempResult ) )
600 {
601 prefetched = tempResult;
602 filterContents( prefetched );
603 return true;
604 }
605 }
606
607
608
609 for ( EntryFilter filter : filters )
610 {
611
612 if ( ! ( accepted &= filter.accept( getOperationContext(), tempResult ) ) )
613 {
614 continue outer;
615 }
616 }
617
618
619
620
621 prefetched = tempResult;
622 filterContents( prefetched );
623 return true;
624 }
625
626 prefetched = null;
627 return false;
628 }
629
630
631
632
633
634
635
636
637 public Iterator<ClonedServerEntry> iterator()
638 {
639 return new CursorIterator<ClonedServerEntry>( this );
640 }
641 }