View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
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   * DSML Decorator for SearchRequest
66   *
67   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
68   */
69  public class SearchRequestDsml
70      extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone>
71      implements SearchRequest
72  {
73      /** A temporary storage for a terminal Filter */
74      private Filter terminalFilter;
75  
76      /** The current filter. This is used while decoding a PDU */
77      private Filter currentFilter;
78  
79      /** The global filter. This is used while decoding a PDU */
80      private Filter topFilter;
81  
82  
83      /**
84       * Creates a new getDecoratedMessage() of SearchRequestDsml.
85       * 
86       * @param codec The LDAP Service to use
87       */
88      public SearchRequestDsml( LdapApiService codec )
89      {
90          super( codec, new SearchRequestImpl() );
91      }
92  
93  
94      /**
95       * Creates a new getDecoratedMessage() of SearchRequestDsml.
96       *
97       * @param codec The LDAP Service to use
98       * @param ldapMessage the message to decorate
99       */
100     public SearchRequestDsml( LdapApiService codec, SearchRequest ldapMessage )
101     {
102         super( codec, ldapMessage );
103     }
104 
105 
106     /**
107      * Gets the search filter associated with this search request.
108      *
109      * @return the expression node for the root of the filter expression tree.
110      */
111     public Filter getCodecFilter()
112     {
113         return topFilter;
114     }
115 
116 
117     /**
118      * Gets the search filter associated with this search request.
119      *
120      * @return the expression node for the root of the filter expression tree.
121      * @throws LdapSchemaException If the filter is invalid
122      */
123     public ExprNode getFilterNode() throws LdapSchemaException
124     {
125         return transform( topFilter );
126     }
127 
128 
129     /**
130      * Get the terminal filter
131      *
132      * @return Returns the terminal filter.
133      */
134     public Filter getTerminalFilter()
135     {
136         return terminalFilter;
137     }
138 
139 
140     /**
141      * Set the terminal filter
142      *
143      * @param terminalFilter the teminalFilter.
144      */
145     public void setTerminalFilter( Filter terminalFilter )
146     {
147         this.terminalFilter = terminalFilter;
148     }
149 
150 
151     /**
152      * set the currentFilter to its parent
153      */
154     public void endCurrentConnectorFilter()
155     {
156         currentFilter = currentFilter.getParent();
157     }
158 
159 
160     /**
161      * Add a current filter. We have two cases :
162      * <ul>
163      *   <li>there is no previous current filter : the filter
164      *     is the top level filter</li>
165      *   <li>there is a previous current filter : the filter is added
166      *     to the currentFilter set, and the current filter is changed</li>
167      * </ul>
168      * In any case, the previous current filter will always be a
169      * ConnectorFilter when this method is called.
170      *
171      * @param localFilter The filter to set.
172      * @throws DecoderException If the added filter is invalid
173      */
174     public void addCurrentFilter( Filter localFilter ) throws DecoderException
175     {
176         if ( currentFilter != null )
177         {
178             // Ok, we have a parent. The new Filter will be added to
179             // this parent, and will become the currentFilter if it's a connector.
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             // No parent. This Filter will become the root.
191             currentFilter = localFilter;
192             currentFilter.setParent( null );
193             topFilter = localFilter;
194         }
195     }
196 
197 
198     /**
199      * Transform the Filter part of a SearchRequest to an ExprNode
200      *
201      * @param filter The filter to be transformed
202      * @return An ExprNode
203      * @throws LdapSchemaException If the filter contains a wrong schema element
204      */
205     @SuppressWarnings({ "rawtypes" })
206     private ExprNode transform( Filter filter ) throws LdapSchemaException
207     {
208         if ( filter != null )
209         {
210             // Transform OR, AND or NOT leaves
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                 // Loop on all AND/OR children
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                 // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
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                     // Transform =, >=, <=, ~= filters
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                     // Transform Substring filters
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                     // Transform Extensible Match Filter
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             // We have found nothing to transform. Return null then.
340             return null;
341         }
342     }
343 
344 
345     /**
346      * {@inheritDoc}
347      */
348     @Override
349     public MessageTypeEnum getType()
350     {
351         return getDecorated().getType();
352     }
353 
354 
355     /**
356      * {@inheritDoc}
357      */
358     @Override
359     public Element toDsml( Element root )
360     {
361         Element element = super.toDsml( root );
362 
363         SearchRequest request = getDecorated();
364 
365         // Dn
366         if ( request.getBase() != null )
367         {
368             element.addAttribute( DsmlLiterals.DN, request.getBase().getName() );
369         }
370 
371         // Scope
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         // DerefAliases
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         // SizeLimit
415         if ( request.getSizeLimit() != 0L )
416         {
417             element.addAttribute( DsmlLiterals.SIZE_LIMIT, Long.toString( request.getSizeLimit() ) );
418         }
419 
420         // TimeLimit
421         if ( request.getTimeLimit() != 0 )
422         {
423             element.addAttribute( DsmlLiterals.TIME_LIMIT, Integer.toString( request.getTimeLimit() ) );
424         }
425 
426         // TypesOnly
427         if ( request.getTypesOnly() )
428         {
429             element.addAttribute( DsmlLiterals.TYPES_ONLY,  DsmlLiterals.TRUE );
430         }
431 
432         // Filter
433         Element filterElement = element.addElement( DsmlLiterals.FILTER );
434         toDsml( filterElement, request.getFilter() );
435 
436         // Attributes
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      * Recursively converts the filter of the Search Request into a DSML representation and adds 
455      * it to the XML Element corresponding to the Search Request
456      *
457      * @param element
458      *      the parent Element
459      * @param filter
460      *      the filter to convert
461      */
462     private void toDsml( Element element, ExprNode filter )
463     {
464         // AND FILTER
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         // OR FILTER
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         // NOT FILTER
491         else if ( filter instanceof NotNode )
492         {
493             Element newElement = element.addElement( DsmlLiterals.NOT );
494 
495             toDsml( newElement, ( ( NotNode ) filter ).getFirstChild() );
496         }
497 
498         // SUBSTRING FILTER
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         // APPROXMATCH, EQUALITYMATCH, GREATEROREQUALS & LESSOREQUAL FILTERS
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             // it is a LessEqNode )
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         // PRESENT FILTER
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         // EXTENSIBLEMATCH
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      * {@inheritDoc}
629      */
630     @Override
631     public MessageTypeEnum[] getResponseTypes()
632     {
633         return getDecorated().getResponseTypes();
634     }
635 
636 
637     /**
638      * {@inheritDoc}
639      */
640     @Override
641     public Dn getBase()
642     {
643         return getDecorated().getBase();
644     }
645 
646 
647     /**
648      * {@inheritDoc}
649      */
650     @Override
651     public SearchRequest setBase( Dn baseDn )
652     {
653         getDecorated().setBase( baseDn );
654 
655         return this;
656     }
657 
658 
659     /**
660      * {@inheritDoc}
661      */
662     @Override
663     public SearchScope getScope()
664     {
665         return getDecorated().getScope();
666     }
667 
668 
669     /**
670      * {@inheritDoc}
671      */
672     @Override
673     public SearchRequest setScope( SearchScope scope )
674     {
675         getDecorated().setScope( scope );
676 
677         return this;
678     }
679 
680 
681     /**
682      * {@inheritDoc}
683      */
684     @Override
685     public AliasDerefMode getDerefAliases()
686     {
687         return getDecorated().getDerefAliases();
688     }
689 
690 
691     /**
692      * {@inheritDoc}
693      */
694     @Override
695     public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
696     {
697         getDecorated().setDerefAliases( aliasDerefAliases );
698 
699         return this;
700     }
701 
702 
703     /**
704      * {@inheritDoc}
705      */
706     @Override
707     public long getSizeLimit()
708     {
709         return getDecorated().getSizeLimit();
710     }
711 
712 
713     /**
714      * {@inheritDoc}
715      */
716     @Override
717     public SearchRequest setSizeLimit( long entriesMax )
718     {
719         getDecorated().setSizeLimit( entriesMax );
720 
721         return this;
722     }
723 
724 
725     /**
726      * {@inheritDoc}
727      */
728     @Override
729     public int getTimeLimit()
730     {
731         return getDecorated().getTimeLimit();
732     }
733 
734 
735     /**
736      * {@inheritDoc}
737      */
738     @Override
739     public SearchRequest setTimeLimit( int secondsMax )
740     {
741         getDecorated().setTimeLimit( secondsMax );
742 
743         return this;
744     }
745 
746 
747     /**
748      * {@inheritDoc}
749      */
750     @Override
751     public boolean getTypesOnly()
752     {
753         return getDecorated().getTypesOnly();
754     }
755 
756 
757     /**
758      * {@inheritDoc}
759      */
760     @Override
761     public SearchRequest setTypesOnly( boolean typesOnly )
762     {
763         getDecorated().setTypesOnly( typesOnly );
764 
765         return this;
766     }
767 
768 
769     /**
770      * {@inheritDoc}
771      */
772     @Override
773     public ExprNode getFilter()
774     {
775         return getDecorated().getFilter();
776     }
777 
778 
779     /**
780      * {@inheritDoc}
781      */
782     @Override
783     public SearchRequest setFilter( ExprNode filter )
784     {
785         getDecorated().setFilter( filter );
786 
787         return this;
788     }
789 
790 
791     /**
792      * {@inheritDoc}
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      * {@inheritDoc}
805      */
806     @Override
807     public List<String> getAttributes()
808     {
809         return getDecorated().getAttributes();
810     }
811 
812 
813     /**
814      * {@inheritDoc}
815      */
816     @Override
817     public SearchRequest addAttributes( String... attributes )
818     {
819         getDecorated().addAttributes( attributes );
820 
821         return this;
822     }
823 
824 
825     /**
826      * {@inheritDoc}
827      */
828     @Override
829     public SearchRequest removeAttribute( String attribute )
830     {
831         getDecorated().removeAttribute( attribute );
832 
833         return this;
834     }
835 
836 
837     /**
838      * {@inheritDoc}
839      */
840     @Override
841     public SearchRequest setMessageId( int messageId )
842     {
843         return ( SearchRequest ) super.setMessageId( messageId );
844     }
845 
846 
847     /**
848      * {@inheritDoc}
849      */
850     @Override
851     public SearchRequest addControl( Control control )
852     {
853         return ( SearchRequest ) super.addControl( control );
854     }
855 
856 
857     /**
858      * {@inheritDoc}
859      */
860     @Override
861     public SearchRequest addAllControls( Control[] controls )
862     {
863         return ( SearchRequest ) super.addAllControls( controls );
864     }
865 
866 
867     /**
868      * {@inheritDoc}
869      */
870     @Override
871     public SearchRequest removeControl( Control control )
872     {
873         return ( SearchRequest ) super.removeControl( control );
874     }
875 
876 
877     /**
878      * {@inheritDoc}
879      */
880     @Override
881     public boolean isFollowReferrals()
882     {
883         return getDecorated().isFollowReferrals();
884     }
885 
886 
887     /**
888      * {@inheritDoc}
889      */
890     @Override
891     public SearchRequest followReferrals()
892     {
893         return getDecorated().followReferrals();
894     }
895 
896 
897     /**
898      * {@inheritDoc}
899      */
900     @Override
901     public boolean isIgnoreReferrals()
902     {
903         return getDecorated().isIgnoreReferrals();
904     }
905 
906 
907     /**
908      * {@inheritDoc}
909      */
910     @Override
911     public SearchRequest ignoreReferrals()
912     {
913         return getDecorated().ignoreReferrals();
914     }
915 }