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   *    http://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.directory.api.asn1.DecoderException;
27  import org.apache.directory.api.dsmlv2.ParserUtils;
28  import org.apache.directory.api.ldap.codec.api.LdapApiService;
29  import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
30  import org.apache.directory.api.ldap.model.entry.Value;
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.apache.directory.api.ldap.model.filter.AndNode;
33  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
34  import org.apache.directory.api.ldap.model.filter.BranchNode;
35  import org.apache.directory.api.ldap.model.filter.EqualityNode;
36  import org.apache.directory.api.ldap.model.filter.ExprNode;
37  import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
38  import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
39  import org.apache.directory.api.ldap.model.filter.LeafNode;
40  import org.apache.directory.api.ldap.model.filter.LessEqNode;
41  import org.apache.directory.api.ldap.model.filter.NotNode;
42  import org.apache.directory.api.ldap.model.filter.OrNode;
43  import org.apache.directory.api.ldap.model.filter.PresenceNode;
44  import org.apache.directory.api.ldap.model.filter.SimpleNode;
45  import org.apache.directory.api.ldap.model.filter.SubstringNode;
46  import org.apache.directory.api.ldap.model.message.AliasDerefMode;
47  import org.apache.directory.api.ldap.model.message.Control;
48  import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
49  import org.apache.directory.api.ldap.model.message.SearchRequest;
50  import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
51  import org.apache.directory.api.ldap.model.message.SearchResultDone;
52  import org.apache.directory.api.ldap.model.message.SearchScope;
53  import org.apache.directory.api.ldap.model.name.Dn;
54  import org.dom4j.Element;
55  import org.dom4j.Namespace;
56  import org.dom4j.QName;
57  
58  
59  /**
60   * DSML Decorator for SearchRequest
61   *
62   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
63   */
64  public class SearchRequestDsml
65      extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone>
66      implements SearchRequest
67  {
68      /** Some string constants */
69      private static final String DEREF_ALIASES = "derefAliases";
70      private static final String NAME = "name";
71      private static final String VALUE = "value";
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      */
122     public ExprNode getFilterNode()
123     {
124         return transform( topFilter );
125     }
126 
127 
128     /**
129      * Get the terminal filter
130      *
131      * @return Returns the terminal filter.
132      */
133     public Filter getTerminalFilter()
134     {
135         return terminalFilter;
136     }
137 
138 
139     /**
140      * Set the terminal filter
141      *
142      * @param terminalFilter the teminalFilter.
143      */
144     public void setTerminalFilter( Filter terminalFilter )
145     {
146         this.terminalFilter = terminalFilter;
147     }
148 
149 
150     /**
151      * set the currentFilter to its parent
152      */
153     public void endCurrentConnectorFilter()
154     {
155         currentFilter = currentFilter.getParent();
156     }
157 
158 
159     /**
160      * Add a current filter. We have two cases :
161      * <ul>
162      *   <li>there is no previous current filter : the filter
163      *     is the top level filter</li>
164      *   <li>there is a previous current filter : the filter is added
165      *     to the currentFilter set, and the current filter is changed</li>
166      * </ul>
167      * In any case, the previous current filter will always be a
168      * ConnectorFilter when this method is called.
169      *
170      * @param localFilter The filter to set.
171      * @throws DecoderException If the added filter is invalid
172      */
173     public void addCurrentFilter( Filter localFilter ) throws DecoderException
174     {
175         if ( currentFilter != null )
176         {
177             // Ok, we have a parent. The new Filter will be added to
178             // this parent, and will become the currentFilter if it's a connector.
179             ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
180             localFilter.setParent( currentFilter );
181 
182             if ( localFilter instanceof ConnectorFilter )
183             {
184                 currentFilter = localFilter;
185             }
186         }
187         else
188         {
189             // No parent. This Filter will become the root.
190             currentFilter = localFilter;
191             currentFilter.setParent( null );
192             topFilter = localFilter;
193         }
194     }
195 
196 
197     /**
198      * Transform the Filter part of a SearchRequest to an ExprNode
199      *
200      * @param filter The filter to be transformed
201      * @return An ExprNode
202      */
203     @SuppressWarnings(
204         { "unchecked", "rawtypes" })
205     private ExprNode transform( Filter filter )
206     {
207         if ( filter != null )
208         {
209             // Transform OR, AND or NOT leaves
210             if ( filter instanceof ConnectorFilter )
211             {
212                 BranchNode branch = null;
213 
214                 if ( filter instanceof AndFilter )
215                 {
216                     branch = new AndNode();
217                 }
218                 else if ( filter instanceof OrFilter )
219                 {
220                     branch = new OrNode();
221                 }
222                 else if ( filter instanceof NotFilter )
223                 {
224                     branch = new NotNode();
225                 }
226 
227                 List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
228 
229                 // Loop on all AND/OR children
230                 if ( filtersSet != null )
231                 {
232                     for ( Filter node : filtersSet )
233                     {
234                         branch.addNode( transform( node ) );
235                     }
236                 }
237 
238                 return branch;
239             }
240             else
241             {
242                 // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
243                 LeafNode branch = null;
244 
245                 if ( filter instanceof PresentFilter )
246                 {
247                     branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
248                 }
249                 else if ( filter instanceof AttributeValueAssertionFilter )
250                 {
251                     AttributeValueAssertionFilter avaFilter = ( AttributeValueAssertionFilter ) filter;
252 
253                     AttributeValueAssertion ava = avaFilter.getAssertion();
254 
255                     // Transform =, >=, <=, ~= filters
256                     int filterType = avaFilter.getFilterType();
257                     switch ( filterType )
258                     {
259                         case LdapCodecConstants.EQUALITY_MATCH_FILTER:
260                             branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertionValue() );
261                             break;
262 
263                         case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
264                             branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
265                             break;
266 
267                         case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
268                             branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
269                             break;
270 
271                         case LdapCodecConstants.APPROX_MATCH_FILTER:
272                             branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertionValue() );
273                             break;
274 
275                         default:
276                             throw new IllegalStateException( "Unexpected filter type " + filterType );
277                     }
278 
279                 }
280                 else if ( filter instanceof SubstringFilter )
281                 {
282                     // Transform Substring filters
283                     SubstringFilter substrFilter = ( SubstringFilter ) filter;
284                     String initialString = null;
285                     String finalString = null;
286                     List<String> anyString = null;
287 
288                     if ( substrFilter.getInitialSubstrings() != null )
289                     {
290                         initialString = substrFilter.getInitialSubstrings();
291                     }
292 
293                     if ( substrFilter.getFinalSubstrings() != null )
294                     {
295                         finalString = substrFilter.getFinalSubstrings();
296                     }
297 
298                     if ( substrFilter.getAnySubstrings() != null )
299                     {
300                         anyString = new ArrayList<String>();
301 
302                         for ( String any : substrFilter.getAnySubstrings() )
303                         {
304                             anyString.add( any );
305                         }
306                     }
307 
308                     branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
309                 }
310                 else if ( filter instanceof ExtensibleMatchFilter )
311                 {
312                     // Transform Extensible Match Filter
313                     ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
314                     String matchingRule = null;
315 
316                     Value<?> value = extFilter.getMatchValue();
317 
318                     if ( extFilter.getMatchingRule() != null )
319                     {
320                         matchingRule = extFilter.getMatchingRule();
321                     }
322 
323                     branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
324                 }
325 
326                 return branch;
327             }
328         }
329         else
330         {
331             // We have found nothing to transform. Return null then.
332             return null;
333         }
334     }
335 
336 
337     /**
338      * {@inheritDoc}
339      */
340     public MessageTypeEnum getType()
341     {
342         return getDecorated().getType();
343     }
344 
345 
346     /**
347      * {@inheritDoc}
348      */
349     public Element toDsml( Element root )
350     {
351         Element element = super.toDsml( root );
352 
353         SearchRequest request = getDecorated();
354 
355         // Dn
356         if ( request.getBase() != null )
357         {
358             element.addAttribute( "dn", request.getBase().getName() );
359         }
360 
361         // Scope
362         SearchScope scope = request.getScope();
363         if ( scope != null )
364         {
365             if ( scope == SearchScope.OBJECT )
366             {
367                 element.addAttribute( "scope", "baseObject" );
368             }
369             else if ( scope == SearchScope.ONELEVEL )
370             {
371                 element.addAttribute( "scope", "singleLevel" );
372             }
373             else if ( scope == SearchScope.SUBTREE )
374             {
375                 element.addAttribute( "scope", "wholeSubtree" );
376             }
377         }
378 
379         // DerefAliases
380         AliasDerefMode derefAliases = request.getDerefAliases();
381 
382         switch ( derefAliases )
383         {
384             case NEVER_DEREF_ALIASES:
385                 element.addAttribute( DEREF_ALIASES, "neverDerefAliases" );
386                 break;
387 
388             case DEREF_ALWAYS:
389                 element.addAttribute( DEREF_ALIASES, "derefAlways" );
390                 break;
391 
392             case DEREF_FINDING_BASE_OBJ:
393                 element.addAttribute( DEREF_ALIASES, "derefFindingBaseObj" );
394                 break;
395 
396             case DEREF_IN_SEARCHING:
397                 element.addAttribute( DEREF_ALIASES, "derefInSearching" );
398                 break;
399 
400             default:
401                 throw new IllegalStateException( "Unexpected deref alias mode " + derefAliases );
402         }
403 
404         // SizeLimit
405         if ( request.getSizeLimit() != 0L )
406         {
407             element.addAttribute( "sizeLimit", "" + request.getSizeLimit() );
408         }
409 
410         // TimeLimit
411         if ( request.getTimeLimit() != 0 )
412         {
413             element.addAttribute( "timeLimit", "" + request.getTimeLimit() );
414         }
415 
416         // TypesOnly
417         if ( request.getTypesOnly() )
418         {
419             element.addAttribute( "typesOnly", "true" );
420         }
421 
422         // Filter
423         Element filterElement = element.addElement( "filter" );
424         toDsml( filterElement, request.getFilter() );
425 
426         // Attributes
427         List<String> attributes = request.getAttributes();
428 
429         if ( attributes.size() > 0 )
430         {
431             Element attributesElement = element.addElement( "attributes" );
432 
433             for ( String entryAttribute : attributes )
434             {
435                 attributesElement.addElement( "attribute" ).addAttribute( NAME, entryAttribute );
436             }
437         }
438 
439         return element;
440     }
441 
442 
443     /**
444      * Recursively converts the filter of the Search Request into a DSML representation and adds 
445      * it to the XML Element corresponding to the Search Request
446      *
447      * @param element
448      *      the parent Element
449      * @param filter
450      *      the filter to convert
451      */
452     private void toDsml( Element element, ExprNode filter )
453     {
454         // AND FILTER
455         if ( filter instanceof AndNode )
456         {
457             Element newElement = element.addElement( "and" );
458 
459             List<ExprNode> filterList = ( ( AndNode ) filter ).getChildren();
460 
461             for ( int i = 0; i < filterList.size(); i++ )
462             {
463                 toDsml( newElement, filterList.get( i ) );
464             }
465         }
466 
467         // OR FILTER
468         else if ( filter instanceof OrNode )
469         {
470             Element newElement = element.addElement( "or" );
471 
472             List<ExprNode> filterList = ( ( OrNode ) filter ).getChildren();
473 
474             for ( int i = 0; i < filterList.size(); i++ )
475             {
476                 toDsml( newElement, filterList.get( i ) );
477             }
478         }
479 
480         // NOT FILTER
481         else if ( filter instanceof NotNode )
482         {
483             Element newElement = element.addElement( "not" );
484 
485             toDsml( newElement, ( ( NotNode ) filter ).getFirstChild() );
486         }
487 
488         // SUBSTRING FILTER
489         else if ( filter instanceof SubstringNode )
490         {
491             Element newElement = element.addElement( "substrings" );
492 
493             SubstringNode substringFilter = ( SubstringNode ) filter;
494 
495             newElement.addAttribute( NAME, substringFilter.getAttribute() );
496 
497             String initial = substringFilter.getInitial();
498 
499             if ( ( initial != null ) && ( !"".equals( initial ) ) )
500             {
501                 newElement.addElement( "initial" ).setText( initial );
502             }
503 
504             List<String> anyList = substringFilter.getAny();
505 
506             for ( int i = 0; i < anyList.size(); i++ )
507             {
508                 newElement.addElement( "any" ).setText( anyList.get( i ) );
509             }
510 
511             String finalString = substringFilter.getFinal();
512 
513             if ( ( finalString != null ) && ( !"".equals( finalString ) ) )
514             {
515                 newElement.addElement( "final" ).setText( finalString );
516             }
517         }
518 
519         // APPROXMATCH, EQUALITYMATCH, GREATEROREQUALS & LESSOREQUAL FILTERS
520         else if ( filter instanceof SimpleNode )
521         {
522             Element newElement = null;
523 
524             if ( filter instanceof ApproximateNode )
525             {
526                 newElement = element.addElement( "approxMatch" );
527             }
528             else if ( filter instanceof EqualityNode )
529             {
530                 newElement = element.addElement( "equalityMatch" );
531             }
532             else if ( filter instanceof GreaterEqNode )
533             {
534                 newElement = element.addElement( "greaterOrEqual" );
535             }
536             else
537             // it is a LessEqNode )
538             {
539                 newElement = element.addElement( "lessOrEqual" );
540             }
541 
542             String attributeName = ( ( SimpleNode<?> ) filter ).getAttribute();
543             newElement.addAttribute( NAME, attributeName );
544 
545             Value<?> value = ( ( SimpleNode<?> ) filter ).getValue();
546             if ( value != null )
547             {
548                 if ( ParserUtils.needsBase64Encoding( value ) )
549                 {
550                     Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
551                     Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
552                     element.getDocument().getRootElement().add( xsdNamespace );
553                     element.getDocument().getRootElement().add( xsiNamespace );
554 
555                     Element valueElement = newElement.addElement( VALUE ).addText(
556                         ParserUtils.base64Encode( value ) );
557                     valueElement
558                         .addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
559                 }
560                 else
561                 {
562                     newElement.addElement( VALUE ).setText( value.getString() );
563                 }
564             }
565         }
566 
567         // PRESENT FILTER
568         else if ( filter instanceof PresenceNode )
569         {
570             Element newElement = element.addElement( "present" );
571 
572             newElement.addAttribute( NAME, ( ( PresenceNode ) filter ).getAttribute() );
573         }
574 
575         // EXTENSIBLEMATCH
576         else if ( filter instanceof ExtensibleNode )
577         {
578             Element newElement = element.addElement( "extensibleMatch" );
579 
580             Value<?> value = ( ( ExtensibleNode ) filter ).getValue();
581             if ( value != null )
582             {
583                 if ( ParserUtils.needsBase64Encoding( value ) )
584                 {
585                     Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
586                     Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
587                     element.getDocument().getRootElement().add( xsdNamespace );
588                     element.getDocument().getRootElement().add( xsiNamespace );
589 
590                     Element valueElement = newElement.addElement( VALUE ).addText(
591                         ParserUtils.base64Encode( value.getValue() ) );
592                     valueElement.addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
593                 }
594                 else
595                 {
596                     newElement.addElement( VALUE ).setText( value.getString() );
597                 }
598             }
599 
600             if ( ( ( ExtensibleNode ) filter ).hasDnAttributes() )
601             {
602                 newElement.addAttribute( "dnAttributes", "true" );
603             }
604 
605             String matchingRule = ( ( ExtensibleNode ) filter ).getMatchingRuleId();
606             if ( ( matchingRule != null ) && ( "".equals( matchingRule ) ) )
607             {
608                 newElement.addAttribute( "matchingRule", matchingRule );
609             }
610         }
611     }
612 
613 
614     /**
615      * {@inheritDoc}
616      */
617     public MessageTypeEnum[] getResponseTypes()
618     {
619         return getDecorated().getResponseTypes();
620     }
621 
622 
623     /**
624      * {@inheritDoc}
625      */
626     public Dn getBase()
627     {
628         return getDecorated().getBase();
629     }
630 
631 
632     /**
633      * {@inheritDoc}
634      */
635     public SearchRequest setBase( Dn baseDn )
636     {
637         getDecorated().setBase( baseDn );
638 
639         return this;
640     }
641 
642 
643     /**
644      * {@inheritDoc}
645      */
646     public SearchScope getScope()
647     {
648         return getDecorated().getScope();
649     }
650 
651 
652     /**
653      * {@inheritDoc}
654      */
655     public SearchRequest setScope( SearchScope scope )
656     {
657         getDecorated().setScope( scope );
658 
659         return this;
660     }
661 
662 
663     /**
664      * {@inheritDoc}
665      */
666     public AliasDerefMode getDerefAliases()
667     {
668         return getDecorated().getDerefAliases();
669     }
670 
671 
672     /**
673      * {@inheritDoc}
674      */
675     public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
676     {
677         getDecorated().setDerefAliases( aliasDerefAliases );
678 
679         return this;
680     }
681 
682 
683     /**
684      * {@inheritDoc}
685      */
686     public long getSizeLimit()
687     {
688         return getDecorated().getSizeLimit();
689     }
690 
691 
692     /**
693      * {@inheritDoc}
694      */
695     public SearchRequest setSizeLimit( long entriesMax )
696     {
697         getDecorated().setSizeLimit( entriesMax );
698 
699         return this;
700     }
701 
702 
703     /**
704      * {@inheritDoc}
705      */
706     public int getTimeLimit()
707     {
708         return getDecorated().getTimeLimit();
709     }
710 
711 
712     /**
713      * {@inheritDoc}
714      */
715     public SearchRequest setTimeLimit( int secondsMax )
716     {
717         getDecorated().setTimeLimit( secondsMax );
718 
719         return this;
720     }
721 
722 
723     /**
724      * {@inheritDoc}
725      */
726     public boolean getTypesOnly()
727     {
728         return getDecorated().getTypesOnly();
729     }
730 
731 
732     /**
733      * {@inheritDoc}
734      */
735     public SearchRequest setTypesOnly( boolean typesOnly )
736     {
737         getDecorated().setTypesOnly( typesOnly );
738 
739         return this;
740     }
741 
742 
743     /**
744      * {@inheritDoc}
745      */
746     public ExprNode getFilter()
747     {
748         return getDecorated().getFilter();
749     }
750 
751 
752     /**
753      * {@inheritDoc}
754      */
755     public SearchRequest setFilter( ExprNode filter )
756     {
757         getDecorated().setFilter( filter );
758 
759         return this;
760     }
761 
762 
763     /**
764      * {@inheritDoc}
765      */
766     public SearchRequest setFilter( String filter ) throws LdapException
767     {
768         getDecorated().setFilter( filter );
769 
770         return this;
771     }
772 
773 
774     /**
775      * {@inheritDoc}
776      */
777     public List<String> getAttributes()
778     {
779         return getDecorated().getAttributes();
780     }
781 
782 
783     /**
784      * {@inheritDoc}
785      */
786     public SearchRequest addAttributes( String... attributes )
787     {
788         getDecorated().addAttributes( attributes );
789 
790         return this;
791     }
792 
793 
794     /**
795      * {@inheritDoc}
796      */
797     public SearchRequest removeAttribute( String attribute )
798     {
799         getDecorated().removeAttribute( attribute );
800 
801         return this;
802     }
803 
804 
805     /**
806      * {@inheritDoc}
807      */
808     public SearchRequest setMessageId( int messageId )
809     {
810         return ( SearchRequest ) super.setMessageId( messageId );
811     }
812 
813 
814     /**
815      * {@inheritDoc}
816      */
817     public SearchRequest addControl( Control control )
818     {
819         return ( SearchRequest ) super.addControl( control );
820     }
821 
822 
823     /**
824      * {@inheritDoc}
825      */
826     public SearchRequest addAllControls( Control[] controls )
827     {
828         return ( SearchRequest ) super.addAllControls( controls );
829     }
830 
831 
832     /**
833      * {@inheritDoc}
834      */
835     public SearchRequest removeControl( Control control )
836     {
837         return ( SearchRequest ) super.removeControl( control );
838     }
839 
840 
841     /**
842      * {@inheritDoc}
843      */
844     public boolean isFollowReferrals()
845     {
846         return getDecorated().isFollowReferrals();
847     }
848 
849 
850     /**
851      * {@inheritDoc}
852      */
853     public SearchRequest followReferrals()
854     {
855         return getDecorated().followReferrals();
856     }
857 
858 
859     /**
860      * {@inheritDoc}
861      */
862     public boolean isIgnoreReferrals()
863     {
864         return getDecorated().isIgnoreReferrals();
865     }
866 
867 
868     /**
869      * {@inheritDoc}
870      */
871     public SearchRequest ignoreReferrals()
872     {
873         return getDecorated().ignoreReferrals();
874     }
875 }