001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.dsmlv2.request; 021 022 023import java.util.ArrayList; 024import java.util.List; 025 026import org.apache.commons.text.StringEscapeUtils; 027import org.apache.directory.api.asn1.DecoderException; 028import org.apache.directory.api.dsmlv2.DsmlLiterals; 029import org.apache.directory.api.dsmlv2.ParserUtils; 030import org.apache.directory.api.i18n.I18n; 031import org.apache.directory.api.ldap.codec.api.LdapApiService; 032import org.apache.directory.api.ldap.codec.api.LdapCodecConstants; 033import org.apache.directory.api.ldap.model.entry.Value; 034import org.apache.directory.api.ldap.model.exception.LdapException; 035import org.apache.directory.api.ldap.model.exception.LdapSchemaException; 036import org.apache.directory.api.ldap.model.filter.AndNode; 037import org.apache.directory.api.ldap.model.filter.ApproximateNode; 038import org.apache.directory.api.ldap.model.filter.BranchNode; 039import org.apache.directory.api.ldap.model.filter.EqualityNode; 040import org.apache.directory.api.ldap.model.filter.ExprNode; 041import org.apache.directory.api.ldap.model.filter.ExtensibleNode; 042import org.apache.directory.api.ldap.model.filter.GreaterEqNode; 043import org.apache.directory.api.ldap.model.filter.LeafNode; 044import org.apache.directory.api.ldap.model.filter.LessEqNode; 045import org.apache.directory.api.ldap.model.filter.NotNode; 046import org.apache.directory.api.ldap.model.filter.OrNode; 047import org.apache.directory.api.ldap.model.filter.PresenceNode; 048import org.apache.directory.api.ldap.model.filter.SimpleNode; 049import org.apache.directory.api.ldap.model.filter.SubstringNode; 050import org.apache.directory.api.ldap.model.message.AliasDerefMode; 051import org.apache.directory.api.ldap.model.message.Control; 052import org.apache.directory.api.ldap.model.message.MessageTypeEnum; 053import org.apache.directory.api.ldap.model.message.SearchRequest; 054import org.apache.directory.api.ldap.model.message.SearchRequestImpl; 055import org.apache.directory.api.ldap.model.message.SearchResultDone; 056import org.apache.directory.api.ldap.model.message.SearchScope; 057import org.apache.directory.api.ldap.model.name.Dn; 058import org.apache.directory.api.util.Strings; 059import org.dom4j.Element; 060import org.dom4j.Namespace; 061import org.dom4j.QName; 062 063 064/** 065 * DSML Decorator for SearchRequest 066 * 067 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 068 */ 069public class SearchRequestDsml 070 extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone> 071 implements SearchRequest 072{ 073 /** A temporary storage for a terminal Filter */ 074 private Filter terminalFilter; 075 076 /** The current filter. This is used while decoding a PDU */ 077 private Filter currentFilter; 078 079 /** The global filter. This is used while decoding a PDU */ 080 private Filter topFilter; 081 082 083 /** 084 * Creates a new getDecoratedMessage() of SearchRequestDsml. 085 * 086 * @param codec The LDAP Service to use 087 */ 088 public SearchRequestDsml( LdapApiService codec ) 089 { 090 super( codec, new SearchRequestImpl() ); 091 } 092 093 094 /** 095 * Creates a new getDecoratedMessage() of SearchRequestDsml. 096 * 097 * @param codec The LDAP Service to use 098 * @param ldapMessage the message to decorate 099 */ 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}