1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.dsmlv2.request;
21
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.commons.text.StringEscapeUtils;
27 import org.apache.directory.api.asn1.DecoderException;
28 import org.apache.directory.api.dsmlv2.DsmlLiterals;
29 import org.apache.directory.api.dsmlv2.ParserUtils;
30 import org.apache.directory.api.i18n.I18n;
31 import org.apache.directory.api.ldap.codec.api.LdapApiService;
32 import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
33 import org.apache.directory.api.ldap.model.entry.Value;
34 import org.apache.directory.api.ldap.model.exception.LdapException;
35 import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
36 import org.apache.directory.api.ldap.model.filter.AndNode;
37 import org.apache.directory.api.ldap.model.filter.ApproximateNode;
38 import org.apache.directory.api.ldap.model.filter.BranchNode;
39 import org.apache.directory.api.ldap.model.filter.EqualityNode;
40 import org.apache.directory.api.ldap.model.filter.ExprNode;
41 import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
42 import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
43 import org.apache.directory.api.ldap.model.filter.LeafNode;
44 import org.apache.directory.api.ldap.model.filter.LessEqNode;
45 import org.apache.directory.api.ldap.model.filter.NotNode;
46 import org.apache.directory.api.ldap.model.filter.OrNode;
47 import org.apache.directory.api.ldap.model.filter.PresenceNode;
48 import org.apache.directory.api.ldap.model.filter.SimpleNode;
49 import org.apache.directory.api.ldap.model.filter.SubstringNode;
50 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
51 import org.apache.directory.api.ldap.model.message.Control;
52 import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
53 import org.apache.directory.api.ldap.model.message.SearchRequest;
54 import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
55 import org.apache.directory.api.ldap.model.message.SearchResultDone;
56 import org.apache.directory.api.ldap.model.message.SearchScope;
57 import org.apache.directory.api.ldap.model.name.Dn;
58 import org.apache.directory.api.util.Strings;
59 import org.dom4j.Element;
60 import org.dom4j.Namespace;
61 import org.dom4j.QName;
62
63
64
65
66
67
68
69 public class SearchRequestDsml
70 extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone>
71 implements SearchRequest
72 {
73
74 private Filter terminalFilter;
75
76
77 private Filter currentFilter;
78
79
80 private Filter topFilter;
81
82
83
84
85
86
87
88 public SearchRequestDsml( LdapApiService codec )
89 {
90 super( codec, new SearchRequestImpl() );
91 }
92
93
94
95
96
97
98
99
100 public SearchRequestDsml( LdapApiService codec, SearchRequest ldapMessage )
101 {
102 super( codec, ldapMessage );
103 }
104
105
106
107
108
109
110
111 public Filter getCodecFilter()
112 {
113 return topFilter;
114 }
115
116
117
118
119
120
121
122
123 public ExprNode getFilterNode() throws LdapSchemaException
124 {
125 return transform( topFilter );
126 }
127
128
129
130
131
132
133
134 public Filter getTerminalFilter()
135 {
136 return terminalFilter;
137 }
138
139
140
141
142
143
144
145 public void setTerminalFilter( Filter terminalFilter )
146 {
147 this.terminalFilter = terminalFilter;
148 }
149
150
151
152
153
154 public void endCurrentConnectorFilter()
155 {
156 currentFilter = currentFilter.getParent();
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public void addCurrentFilter( Filter localFilter ) throws DecoderException
175 {
176 if ( currentFilter != null )
177 {
178
179
180 ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
181 localFilter.setParent( currentFilter );
182
183 if ( localFilter instanceof ConnectorFilter )
184 {
185 currentFilter = localFilter;
186 }
187 }
188 else
189 {
190
191 currentFilter = localFilter;
192 currentFilter.setParent( null );
193 topFilter = localFilter;
194 }
195 }
196
197
198
199
200
201
202
203
204
205 @SuppressWarnings({ "rawtypes" })
206 private ExprNode transform( Filter filter ) throws LdapSchemaException
207 {
208 if ( filter != null )
209 {
210
211 if ( filter instanceof ConnectorFilter )
212 {
213 BranchNode branch;
214
215 if ( filter instanceof AndFilter )
216 {
217 branch = new AndNode();
218 }
219 else if ( filter instanceof OrFilter )
220 {
221 branch = new OrNode();
222 }
223 else
224 {
225 branch = new NotNode();
226 }
227
228 List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
229
230
231 if ( filtersSet != null )
232 {
233 for ( Filter node : filtersSet )
234 {
235 branch.addNode( transform( node ) );
236 }
237 }
238
239 return branch;
240 }
241 else
242 {
243
244 LeafNode branch = null;
245
246 if ( filter instanceof PresentFilter )
247 {
248 branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
249 }
250 else if ( filter instanceof AttributeValueAssertionFilter )
251 {
252 AttributeValueAssertionFilter avaFilter = ( AttributeValueAssertionFilter ) filter;
253
254 AttributeValueAssertion ava = avaFilter.getAssertion();
255
256
257 int filterType = avaFilter.getFilterType();
258 byte[] value = null;
259
260 if ( ava.getAssertionValue() != null )
261 {
262 value = ava.getAssertionValue().getBytes();
263 }
264
265 switch ( filterType )
266 {
267 case LdapCodecConstants.EQUALITY_MATCH_FILTER:
268 branch = new EqualityNode( ava.getAttributeDesc(), value );
269 break;
270
271 case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
272 branch = new GreaterEqNode( ava.getAttributeDesc(), value );
273 break;
274
275 case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
276 branch = new LessEqNode( ava.getAttributeDesc(), value );
277 break;
278
279 case LdapCodecConstants.APPROX_MATCH_FILTER:
280 branch = new ApproximateNode( ava.getAttributeDesc(), value );
281 break;
282
283 default:
284 throw new IllegalStateException( I18n.err( I18n.ERR_03042_UNEXPECTED_FILTER_TYPE, filterType ) );
285 }
286
287 }
288 else if ( filter instanceof SubstringFilter )
289 {
290
291 SubstringFilter substrFilter = ( SubstringFilter ) filter;
292 String initialString = null;
293 String finalString = null;
294 List<String> anyString = null;
295
296 if ( substrFilter.getInitialSubstrings() != null )
297 {
298 initialString = substrFilter.getInitialSubstrings();
299 }
300
301 if ( substrFilter.getFinalSubstrings() != null )
302 {
303 finalString = substrFilter.getFinalSubstrings();
304 }
305
306 if ( substrFilter.getAnySubstrings() != null )
307 {
308 anyString = new ArrayList<>();
309
310 for ( String any : substrFilter.getAnySubstrings() )
311 {
312 anyString.add( any );
313 }
314 }
315
316 branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
317 }
318 else if ( filter instanceof ExtensibleMatchFilter )
319 {
320
321 ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
322 String matchingRule = null;
323
324 Value value = extFilter.getMatchValue();
325
326 if ( extFilter.getMatchingRule() != null )
327 {
328 matchingRule = extFilter.getMatchingRule();
329 }
330
331 branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
332 }
333
334 return branch;
335 }
336 }
337 else
338 {
339
340 return null;
341 }
342 }
343
344
345
346
347
348 @Override
349 public MessageTypeEnum getType()
350 {
351 return getDecorated().getType();
352 }
353
354
355
356
357
358 @Override
359 public Element toDsml( Element root )
360 {
361 Element element = super.toDsml( root );
362
363 SearchRequest request = getDecorated();
364
365
366 if ( request.getBase() != null )
367 {
368 element.addAttribute( DsmlLiterals.DN, request.getBase().getName() );
369 }
370
371
372 SearchScope scope = request.getScope();
373 if ( scope != null )
374 {
375 if ( scope == SearchScope.OBJECT )
376 {
377 element.addAttribute( DsmlLiterals.SCOPE, DsmlLiterals.BASE_OBJECT );
378 }
379 else if ( scope == SearchScope.ONELEVEL )
380 {
381 element.addAttribute( DsmlLiterals.SCOPE, DsmlLiterals.SINGLE_LEVEL );
382 }
383 else if ( scope == SearchScope.SUBTREE )
384 {
385 element.addAttribute( DsmlLiterals.SCOPE, DsmlLiterals.WHOLE_SUBTREE );
386 }
387 }
388
389
390 AliasDerefMode derefAliases = request.getDerefAliases();
391
392 switch ( derefAliases )
393 {
394 case NEVER_DEREF_ALIASES:
395 element.addAttribute( DsmlLiterals.DEREF_ALIASES, DsmlLiterals.NEVER_DEREF_ALIASES );
396 break;
397
398 case DEREF_ALWAYS:
399 element.addAttribute( DsmlLiterals.DEREF_ALIASES, DsmlLiterals.DEREF_ALWAYS );
400 break;
401
402 case DEREF_FINDING_BASE_OBJ:
403 element.addAttribute( DsmlLiterals.DEREF_ALIASES, DsmlLiterals.DEREF_FINDING_BASE_OBJ );
404 break;
405
406 case DEREF_IN_SEARCHING:
407 element.addAttribute( DsmlLiterals.DEREF_ALIASES, DsmlLiterals.DEREF_IN_SEARCHING );
408 break;
409
410 default:
411 throw new IllegalStateException( I18n.err( I18n.ERR_03043_UNEXPECTED_DEREF_ALIAS, derefAliases ) );
412 }
413
414
415 if ( request.getSizeLimit() != 0L )
416 {
417 element.addAttribute( DsmlLiterals.SIZE_LIMIT, Long.toString( request.getSizeLimit() ) );
418 }
419
420
421 if ( request.getTimeLimit() != 0 )
422 {
423 element.addAttribute( DsmlLiterals.TIME_LIMIT, Integer.toString( request.getTimeLimit() ) );
424 }
425
426
427 if ( request.getTypesOnly() )
428 {
429 element.addAttribute( DsmlLiterals.TYPES_ONLY, DsmlLiterals.TRUE );
430 }
431
432
433 Element filterElement = element.addElement( DsmlLiterals.FILTER );
434 toDsml( filterElement, request.getFilter() );
435
436
437 List<String> attributes = request.getAttributes();
438
439 if ( !attributes.isEmpty() )
440 {
441 Element attributesElement = element.addElement( DsmlLiterals.ATTRIBUTES );
442
443 for ( String entryAttribute : attributes )
444 {
445 attributesElement.addElement( DsmlLiterals.ATTRIBUTE ).addAttribute( DsmlLiterals.NAME, entryAttribute );
446 }
447 }
448
449 return element;
450 }
451
452
453
454
455
456
457
458
459
460
461
462 private void toDsml( Element element, ExprNode filter )
463 {
464
465 if ( filter instanceof AndNode )
466 {
467 Element newElement = element.addElement( DsmlLiterals.AND );
468
469 List<ExprNode> filterList = ( ( AndNode ) filter ).getChildren();
470
471 for ( int i = 0; i < filterList.size(); i++ )
472 {
473 toDsml( newElement, filterList.get( i ) );
474 }
475 }
476
477
478 else if ( filter instanceof OrNode )
479 {
480 Element newElement = element.addElement( DsmlLiterals.OR );
481
482 List<ExprNode> filterList = ( ( OrNode ) filter ).getChildren();
483
484 for ( int i = 0; i < filterList.size(); i++ )
485 {
486 toDsml( newElement, filterList.get( i ) );
487 }
488 }
489
490
491 else if ( filter instanceof NotNode )
492 {
493 Element newElement = element.addElement( DsmlLiterals.NOT );
494
495 toDsml( newElement, ( ( NotNode ) filter ).getFirstChild() );
496 }
497
498
499 else if ( filter instanceof SubstringNode )
500 {
501 Element newElement = element.addElement( DsmlLiterals.SUBSTRINGS );
502
503 SubstringNode substringFilter = ( SubstringNode ) filter;
504
505 newElement.addAttribute( DsmlLiterals.NAME, substringFilter.getAttribute() );
506
507 String initial = substringFilter.getInitial();
508
509 if ( Strings.isNotEmpty( initial ) )
510 {
511 newElement.addElement( DsmlLiterals.INITIAL ).setText( initial );
512 }
513
514 List<String> anyList = substringFilter.getAny();
515
516 for ( int i = 0; i < anyList.size(); i++ )
517 {
518 newElement.addElement( DsmlLiterals.ANY ).setText( anyList.get( i ) );
519 }
520
521 String finalString = substringFilter.getFinal();
522
523 if ( Strings.isNotEmpty( finalString ) )
524 {
525 newElement.addElement( DsmlLiterals.FINAL ).setText( finalString );
526 }
527 }
528
529
530 else if ( filter instanceof SimpleNode )
531 {
532 Element newElement;
533
534 if ( filter instanceof ApproximateNode )
535 {
536 newElement = element.addElement( DsmlLiterals.APPROX_MATCH );
537 }
538 else if ( filter instanceof EqualityNode )
539 {
540 newElement = element.addElement( DsmlLiterals.EQUALITY_MATCH );
541 }
542 else if ( filter instanceof GreaterEqNode )
543 {
544 newElement = element.addElement( DsmlLiterals.GREATER_OR_EQUAL );
545 }
546 else
547
548 {
549 newElement = element.addElement( DsmlLiterals.LESS_OR_EQUAL );
550 }
551
552 String attributeName = ( ( SimpleNode<?> ) filter ).getAttribute();
553 newElement.addAttribute( DsmlLiterals.NAME, attributeName );
554
555 Value value = ( ( SimpleNode<?> ) filter ).getValue();
556
557 if ( value != null )
558 {
559 if ( value.isHumanReadable() )
560 {
561 newElement.addElement( DsmlLiterals.VALUE ).setText( StringEscapeUtils.escapeXml11( value.getString() ) );
562 }
563 else
564 {
565 Namespace xsdNamespace = new Namespace( ParserUtils.XSD, ParserUtils.XML_SCHEMA_URI );
566 Namespace xsiNamespace = new Namespace( ParserUtils.XSI, ParserUtils.XML_SCHEMA_INSTANCE_URI );
567 element.getDocument().getRootElement().add( xsdNamespace );
568 element.getDocument().getRootElement().add( xsiNamespace );
569
570 Element valueElement = newElement.addElement( DsmlLiterals.VALUE ).addText(
571 ParserUtils.base64Encode( value ) );
572 valueElement
573 .addAttribute( new QName( DsmlLiterals.TYPE, xsiNamespace ), ParserUtils.XSD_COLON + ParserUtils.BASE64BINARY );
574 }
575 }
576 }
577
578
579 else if ( filter instanceof PresenceNode )
580 {
581 Element newElement = element.addElement( DsmlLiterals.PRESENT );
582
583 newElement.addAttribute( DsmlLiterals.NAME, ( ( PresenceNode ) filter ).getAttribute() );
584 }
585
586
587 else if ( filter instanceof ExtensibleNode )
588 {
589 Element newElement = element.addElement( DsmlLiterals.EXTENSIBLE_MATCH );
590
591 Value value = ( ( ExtensibleNode ) filter ).getValue();
592
593 if ( value != null )
594 {
595 if ( ParserUtils.needsBase64Encoding( value ) )
596 {
597 Namespace xsdNamespace = new Namespace( ParserUtils.XSD, ParserUtils.XML_SCHEMA_URI );
598 Namespace xsiNamespace = new Namespace( ParserUtils.XSI, ParserUtils.XML_SCHEMA_INSTANCE_URI );
599 element.getDocument().getRootElement().add( xsdNamespace );
600 element.getDocument().getRootElement().add( xsiNamespace );
601
602 Element valueElement = newElement.addElement( DsmlLiterals.VALUE ).addText(
603 ParserUtils.base64Encode( value.getString() ) );
604 valueElement.addAttribute( new QName( DsmlLiterals.TYPE, xsiNamespace ), ParserUtils.XSD_COLON + ParserUtils.BASE64BINARY );
605 }
606 else
607 {
608 newElement.addElement( DsmlLiterals.VALUE ).setText( value.getString() );
609 }
610 }
611
612 if ( ( ( ExtensibleNode ) filter ).hasDnAttributes() )
613 {
614 newElement.addAttribute( DsmlLiterals.DN_ATTRIBUTES, DsmlLiterals.TRUE );
615 }
616
617 String matchingRule = ( ( ExtensibleNode ) filter ).getMatchingRuleId();
618
619 if ( Strings.isNotEmpty( matchingRule ) )
620 {
621 newElement.addAttribute( DsmlLiterals.MATCHING_RULE, matchingRule );
622 }
623 }
624 }
625
626
627
628
629
630 @Override
631 public MessageTypeEnum[] getResponseTypes()
632 {
633 return getDecorated().getResponseTypes();
634 }
635
636
637
638
639
640 @Override
641 public Dn getBase()
642 {
643 return getDecorated().getBase();
644 }
645
646
647
648
649
650 @Override
651 public SearchRequest setBase( Dn baseDn )
652 {
653 getDecorated().setBase( baseDn );
654
655 return this;
656 }
657
658
659
660
661
662 @Override
663 public SearchScope getScope()
664 {
665 return getDecorated().getScope();
666 }
667
668
669
670
671
672 @Override
673 public SearchRequest setScope( SearchScope scope )
674 {
675 getDecorated().setScope( scope );
676
677 return this;
678 }
679
680
681
682
683
684 @Override
685 public AliasDerefMode getDerefAliases()
686 {
687 return getDecorated().getDerefAliases();
688 }
689
690
691
692
693
694 @Override
695 public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
696 {
697 getDecorated().setDerefAliases( aliasDerefAliases );
698
699 return this;
700 }
701
702
703
704
705
706 @Override
707 public long getSizeLimit()
708 {
709 return getDecorated().getSizeLimit();
710 }
711
712
713
714
715
716 @Override
717 public SearchRequest setSizeLimit( long entriesMax )
718 {
719 getDecorated().setSizeLimit( entriesMax );
720
721 return this;
722 }
723
724
725
726
727
728 @Override
729 public int getTimeLimit()
730 {
731 return getDecorated().getTimeLimit();
732 }
733
734
735
736
737
738 @Override
739 public SearchRequest setTimeLimit( int secondsMax )
740 {
741 getDecorated().setTimeLimit( secondsMax );
742
743 return this;
744 }
745
746
747
748
749
750 @Override
751 public boolean getTypesOnly()
752 {
753 return getDecorated().getTypesOnly();
754 }
755
756
757
758
759
760 @Override
761 public SearchRequest setTypesOnly( boolean typesOnly )
762 {
763 getDecorated().setTypesOnly( typesOnly );
764
765 return this;
766 }
767
768
769
770
771
772 @Override
773 public ExprNode getFilter()
774 {
775 return getDecorated().getFilter();
776 }
777
778
779
780
781
782 @Override
783 public SearchRequest setFilter( ExprNode filter )
784 {
785 getDecorated().setFilter( filter );
786
787 return this;
788 }
789
790
791
792
793
794 @Override
795 public SearchRequest setFilter( String filter ) throws LdapException
796 {
797 getDecorated().setFilter( filter );
798
799 return this;
800 }
801
802
803
804
805
806 @Override
807 public List<String> getAttributes()
808 {
809 return getDecorated().getAttributes();
810 }
811
812
813
814
815
816 @Override
817 public SearchRequest addAttributes( String... attributes )
818 {
819 getDecorated().addAttributes( attributes );
820
821 return this;
822 }
823
824
825
826
827
828 @Override
829 public SearchRequest removeAttribute( String attribute )
830 {
831 getDecorated().removeAttribute( attribute );
832
833 return this;
834 }
835
836
837
838
839
840 @Override
841 public SearchRequest setMessageId( int messageId )
842 {
843 return ( SearchRequest ) super.setMessageId( messageId );
844 }
845
846
847
848
849
850 @Override
851 public SearchRequest addControl( Control control )
852 {
853 return ( SearchRequest ) super.addControl( control );
854 }
855
856
857
858
859
860 @Override
861 public SearchRequest addAllControls( Control[] controls )
862 {
863 return ( SearchRequest ) super.addAllControls( controls );
864 }
865
866
867
868
869
870 @Override
871 public SearchRequest removeControl( Control control )
872 {
873 return ( SearchRequest ) super.removeControl( control );
874 }
875
876
877
878
879
880 @Override
881 public boolean isFollowReferrals()
882 {
883 return getDecorated().isFollowReferrals();
884 }
885
886
887
888
889
890 @Override
891 public SearchRequest followReferrals()
892 {
893 return getDecorated().followReferrals();
894 }
895
896
897
898
899
900 @Override
901 public boolean isIgnoreReferrals()
902 {
903 return getDecorated().isIgnoreReferrals();
904 }
905
906
907
908
909
910 @Override
911 public SearchRequest ignoreReferrals()
912 {
913 return getDecorated().ignoreReferrals();
914 }
915 }