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 * http://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.shared.ldap.codec.decorators; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025import java.util.ArrayList; 026import java.util.List; 027 028import org.apache.directory.shared.asn1.DecoderException; 029import org.apache.directory.shared.asn1.EncoderException; 030import org.apache.directory.shared.asn1.ber.Asn1Container; 031import org.apache.directory.shared.asn1.ber.tlv.TLV; 032import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 033import org.apache.directory.shared.i18n.I18n; 034import org.apache.directory.shared.ldap.codec.AttributeValueAssertion; 035import org.apache.directory.shared.ldap.codec.api.LdapApiService; 036import org.apache.directory.shared.ldap.codec.api.LdapConstants; 037import org.apache.directory.shared.ldap.codec.api.LdapMessageContainer; 038import org.apache.directory.shared.ldap.codec.api.MessageDecorator; 039import org.apache.directory.shared.ldap.codec.search.AndFilter; 040import org.apache.directory.shared.ldap.codec.search.AttributeValueAssertionFilter; 041import org.apache.directory.shared.ldap.codec.search.ConnectorFilter; 042import org.apache.directory.shared.ldap.codec.search.ExtensibleMatchFilter; 043import org.apache.directory.shared.ldap.codec.search.Filter; 044import org.apache.directory.shared.ldap.codec.search.NotFilter; 045import org.apache.directory.shared.ldap.codec.search.OrFilter; 046import org.apache.directory.shared.ldap.codec.search.PresentFilter; 047import org.apache.directory.shared.ldap.codec.search.SubstringFilter; 048import org.apache.directory.shared.ldap.model.entry.Value; 049import org.apache.directory.shared.ldap.model.exception.LdapException; 050import org.apache.directory.shared.ldap.model.exception.MessageException; 051import org.apache.directory.shared.ldap.model.filter.AndNode; 052import org.apache.directory.shared.ldap.model.filter.ApproximateNode; 053import org.apache.directory.shared.ldap.model.filter.BranchNode; 054import org.apache.directory.shared.ldap.model.filter.BranchNormalizedVisitor; 055import org.apache.directory.shared.ldap.model.filter.EqualityNode; 056import org.apache.directory.shared.ldap.model.filter.ExprNode; 057import org.apache.directory.shared.ldap.model.filter.ExtensibleNode; 058import org.apache.directory.shared.ldap.model.filter.GreaterEqNode; 059import org.apache.directory.shared.ldap.model.filter.LeafNode; 060import org.apache.directory.shared.ldap.model.filter.LessEqNode; 061import org.apache.directory.shared.ldap.model.filter.NotNode; 062import org.apache.directory.shared.ldap.model.filter.OrNode; 063import org.apache.directory.shared.ldap.model.filter.PresenceNode; 064import org.apache.directory.shared.ldap.model.filter.SimpleNode; 065import org.apache.directory.shared.ldap.model.filter.SubstringNode; 066import org.apache.directory.shared.ldap.model.message.AbandonListener; 067import org.apache.directory.shared.ldap.model.message.AliasDerefMode; 068import org.apache.directory.shared.ldap.model.message.Control; 069import org.apache.directory.shared.ldap.model.message.Message; 070import org.apache.directory.shared.ldap.model.message.MessageTypeEnum; 071import org.apache.directory.shared.ldap.model.message.SearchRequest; 072import org.apache.directory.shared.ldap.model.message.SearchResultDone; 073import org.apache.directory.shared.ldap.model.message.SearchScope; 074import org.apache.directory.shared.ldap.model.name.Dn; 075import org.apache.directory.shared.util.Strings; 076 077 078/** 079 * A decorator for the SearchRequest message 080 * 081 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 082 */ 083public class SearchRequestDecorator extends MessageDecorator<SearchRequest> implements SearchRequest 084{ 085 /** The searchRequest length */ 086 private int searchRequestLength; 087 088 /** The attributeDescriptionList length */ 089 private int attributeDescriptionListLength; 090 091 /** A temporary storage for a terminal Filter */ 092 private Filter terminalFilter; 093 094 /** The current filter. This is used while decoding a PDU */ 095 private Filter currentFilter; 096 097 /** The global filter. This is used while decoding a PDU */ 098 private Filter topFilter; 099 100 /** The SearchRequest TLV id */ 101 private int tlvId; 102 103 104 /** 105 * Makes a SearchRequest encodable. 106 * 107 * @param decoratedMessage the decorated SearchRequest 108 */ 109 public SearchRequestDecorator( LdapApiService codec, SearchRequest decoratedMessage ) 110 { 111 super( codec, decoratedMessage ); 112 } 113 114 115 /** 116 * Stores the encoded length for the SearchRequest 117 * @param searchRequestLength The encoded length 118 */ 119 public void setSearchRequestLength( int searchRequestLength ) 120 { 121 this.searchRequestLength = searchRequestLength; 122 } 123 124 125 /** 126 * @return The encoded SearchRequest's length 127 */ 128 public int getSearchRequestLength() 129 { 130 return searchRequestLength; 131 } 132 133 134 /** 135 * Stores the encoded length for the list of attributes 136 * @param attributeDescriptionListLength The encoded length of the attributes 137 */ 138 public void setAttributeDescriptionListLength( int attributeDescriptionListLength ) 139 { 140 this.attributeDescriptionListLength = attributeDescriptionListLength; 141 } 142 143 144 /** 145 * @return The encoded SearchRequest's attributes length 146 */ 147 public int getAttributeDescriptionListLength() 148 { 149 return attributeDescriptionListLength; 150 } 151 152 153 /** 154 * Set the SearchRequest PDU TLV's Id 155 * @param tlvId The TLV id 156 */ 157 public void setTlvId( int tlvId ) 158 { 159 this.tlvId = tlvId; 160 } 161 162 163 public Filter getCurrentFilter() 164 { 165 return currentFilter; 166 } 167 168 169 /** 170 * Gets the search filter associated with this search request. 171 * 172 * @return the expression node for the root of the filter expression tree. 173 */ 174 public Filter getCodecFilter() 175 { 176 return topFilter; 177 } 178 179 180 /** 181 * Gets the search filter associated with this search request. 182 * 183 * @return the expression node for the root of the filter expression tree. 184 */ 185 public ExprNode getFilterNode() 186 { 187 return transform( topFilter ); 188 } 189 190 191 /** 192 * Get the terminal filter 193 * 194 * @return Returns the terminal filter. 195 */ 196 public Filter getTerminalFilter() 197 { 198 return terminalFilter; 199 } 200 201 202 /** 203 * Set the terminal filter 204 * 205 * @param terminalFilter the teminalFilter. 206 */ 207 public void setTerminalFilter( Filter terminalFilter ) 208 { 209 this.terminalFilter = terminalFilter; 210 } 211 212 213 /** 214 * {@inheritDoc} 215 */ 216 public SearchRequest setFilter( ExprNode filter ) 217 { 218 topFilter = transform( filter ); 219 220 return this; 221 } 222 223 224 /** 225 * {@inheritDoc} 226 */ 227 public SearchRequest setFilter( String filter ) throws LdapException 228 { 229 getDecorated().setFilter( filter ); 230 this.currentFilter = transform( getDecorated().getFilter() ); 231 232 return this; 233 } 234 235 236 /** 237 * Set the current filter 238 * 239 * @param filter The filter to set. 240 */ 241 public void setCurrentFilter( Filter filter ) 242 { 243 currentFilter = filter; 244 } 245 246 247 /** 248 * Add a current filter. We have two cases : 249 * - there is no previous current filter : the filter 250 * is the top level filter 251 * - there is a previous current filter : the filter is added 252 * to the currentFilter set, and the current filter is changed 253 * 254 * In any case, the previous current filter will always be a 255 * ConnectorFilter when this method is called. 256 * 257 * @param localFilter The filter to set. 258 */ 259 public void addCurrentFilter( Filter localFilter ) throws DecoderException 260 { 261 if ( currentFilter != null ) 262 { 263 // Ok, we have a parent. The new Filter will be added to 264 // this parent, and will become the currentFilter if it's a connector. 265 ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter ); 266 localFilter.setParent( currentFilter, currentFilter.getTlvId() ); 267 268 if ( localFilter instanceof ConnectorFilter ) 269 { 270 currentFilter = localFilter; 271 } 272 } 273 else 274 { 275 // No parent. This Filter will become the root. 276 currentFilter = localFilter; 277 currentFilter.setParent( null, tlvId ); 278 topFilter = localFilter; 279 } 280 } 281 282 283 /** 284 * This method is used to clear the filter's stack for terminated elements. An element 285 * is considered as terminated either if : 286 * - it's a final element (ie an element which cannot contains a Filter) 287 * - its current length equals its expected length. 288 * 289 * @param container The container being decoded 290 */ 291 @SuppressWarnings("unchecked") 292 public void unstackFilters( Asn1Container container ) 293 { 294 LdapMessageContainer<MessageDecorator<Message>> ldapMessageContainer = 295 ( LdapMessageContainer<MessageDecorator<Message>> ) container; 296 297 TLV tlv = ldapMessageContainer.getCurrentTLV(); 298 TLV localParent = tlv.getParent(); 299 Filter localFilter = terminalFilter; 300 301 // The parent has been completed, so fold it 302 while ( ( localParent != null ) && ( localParent.getExpectedLength() == 0 ) ) 303 { 304 int parentTlvId = localFilter.getParent() != null ? localFilter.getParent().getTlvId() : localFilter 305 .getParentTlvId(); 306 307 if ( localParent.getId() != parentTlvId ) 308 { 309 localParent = localParent.getParent(); 310 } 311 else 312 { 313 Filter filterParent = localFilter.getParent(); 314 315 // We have a special case with PresentFilter, which has not been 316 // pushed on the stack, so we need to get its parent's parent 317 if ( localFilter instanceof PresentFilter ) 318 { 319 if ( filterParent == null ) 320 { 321 // We don't have parent, get out 322 break; 323 } 324 325 filterParent = filterParent.getParent(); 326 } 327 else if ( filterParent instanceof Filter ) 328 { 329 filterParent = filterParent.getParent(); 330 } 331 332 if ( filterParent instanceof Filter ) 333 { 334 // The parent is a filter ; it will become the new currentFilter 335 // and we will loop again. 336 currentFilter = ( Filter ) filterParent; 337 localFilter = currentFilter; 338 localParent = localParent.getParent(); 339 } 340 else 341 { 342 // We can stop the recursion, we have reached the searchResult Object 343 break; 344 } 345 } 346 } 347 } 348 349 350 /** 351 * Transform the Filter part of a SearchRequest to an ExprNode 352 * 353 * @param filter The filter to be transformed 354 * @return An ExprNode 355 */ 356 @SuppressWarnings( 357 { "unchecked", "rawtypes" }) 358 private ExprNode transform( Filter filter ) 359 { 360 if ( filter != null ) 361 { 362 // Transform OR, AND or NOT leaves 363 if ( filter instanceof ConnectorFilter ) 364 { 365 BranchNode branch = null; 366 367 if ( filter instanceof AndFilter ) 368 { 369 branch = new AndNode(); 370 } 371 else if ( filter instanceof OrFilter ) 372 { 373 branch = new OrNode(); 374 } 375 else if ( filter instanceof NotFilter ) 376 { 377 branch = new NotNode(); 378 } 379 380 List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet(); 381 382 // Loop on all AND/OR children 383 if ( filtersSet != null ) 384 { 385 for ( Filter node : filtersSet ) 386 { 387 branch.addNode( transform( node ) ); 388 } 389 } 390 391 return branch; 392 } 393 else 394 { 395 // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION 396 LeafNode branch = null; 397 398 if ( filter instanceof PresentFilter ) 399 { 400 branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() ); 401 } 402 else if ( filter instanceof AttributeValueAssertionFilter ) 403 { 404 AttributeValueAssertion ava = ( ( AttributeValueAssertionFilter ) filter ).getAssertion(); 405 406 // Transform =, >=, <=, ~= filters 407 switch ( ( ( AttributeValueAssertionFilter ) filter ).getFilterType() ) 408 { 409 case LdapConstants.EQUALITY_MATCH_FILTER: 410 branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertionValue() ); 411 412 break; 413 414 case LdapConstants.GREATER_OR_EQUAL_FILTER: 415 branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertionValue() ); 416 417 break; 418 419 case LdapConstants.LESS_OR_EQUAL_FILTER: 420 branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertionValue() ); 421 422 break; 423 424 case LdapConstants.APPROX_MATCH_FILTER: 425 branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertionValue() ); 426 427 break; 428 } 429 430 } 431 else if ( filter instanceof SubstringFilter ) 432 { 433 // Transform Substring filters 434 SubstringFilter substrFilter = ( SubstringFilter ) filter; 435 String initialString = null; 436 String finalString = null; 437 List<String> anyString = null; 438 439 if ( substrFilter.getInitialSubstrings() != null ) 440 { 441 initialString = substrFilter.getInitialSubstrings(); 442 } 443 444 if ( substrFilter.getFinalSubstrings() != null ) 445 { 446 finalString = substrFilter.getFinalSubstrings(); 447 } 448 449 if ( substrFilter.getAnySubstrings() != null ) 450 { 451 anyString = new ArrayList<String>(); 452 453 for ( String any : substrFilter.getAnySubstrings() ) 454 { 455 anyString.add( any ); 456 } 457 } 458 459 branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString ); 460 } 461 else if ( filter instanceof ExtensibleMatchFilter ) 462 { 463 // Transform Extensible Match Filter 464 ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter; 465 String matchingRule = null; 466 467 Value<?> value = extFilter.getMatchValue(); 468 469 if ( extFilter.getMatchingRule() != null ) 470 { 471 matchingRule = extFilter.getMatchingRule(); 472 } 473 474 branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() ); 475 } 476 477 return branch; 478 } 479 } 480 else 481 { 482 // We have found nothing to transform. Return null then. 483 return null; 484 } 485 } 486 487 488 /** 489 * Transform an ExprNode filter to a Filter 490 * 491 * @param exprNode The filter to be transformed 492 * @return A filter 493 */ 494 private static Filter transform( ExprNode exprNode ) 495 { 496 if ( exprNode != null ) 497 { 498 Filter filter = null; 499 500 // Transform OR, AND or NOT leaves 501 if ( exprNode instanceof BranchNode ) 502 { 503 if ( exprNode instanceof AndNode ) 504 { 505 filter = new AndFilter(); 506 } 507 else if ( exprNode instanceof OrNode ) 508 { 509 filter = new OrFilter(); 510 } 511 else if ( exprNode instanceof NotNode ) 512 { 513 filter = new NotFilter(); 514 } 515 516 List<ExprNode> children = ( ( BranchNode ) exprNode ).getChildren(); 517 518 // Loop on all AND/OR children 519 if ( children != null ) 520 { 521 for ( ExprNode child : children ) 522 { 523 try 524 { 525 ( ( ConnectorFilter ) filter ).addFilter( transform( child ) ); 526 } 527 catch ( DecoderException de ) 528 { 529 return null; 530 } 531 } 532 } 533 } 534 else 535 { 536 if ( exprNode instanceof PresenceNode ) 537 { 538 // Transform Presence Node 539 filter = new PresentFilter(); 540 ( ( PresentFilter ) filter ).setAttributeDescription( ( ( PresenceNode ) exprNode ).getAttribute() ); 541 } 542 else if ( exprNode instanceof SimpleNode<?> ) 543 { 544 if ( exprNode instanceof EqualityNode<?> ) 545 { 546 filter = new AttributeValueAssertionFilter( LdapConstants.EQUALITY_MATCH_FILTER ); 547 AttributeValueAssertion assertion = new AttributeValueAssertion(); 548 assertion.setAttributeDesc( ( ( EqualityNode<?> ) exprNode ).getAttribute() ); 549 assertion.setAssertionValue( ( ( EqualityNode<?> ) exprNode ).getValue() ); 550 ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion ); 551 } 552 else if ( exprNode instanceof GreaterEqNode<?> ) 553 { 554 filter = new AttributeValueAssertionFilter( LdapConstants.GREATER_OR_EQUAL_FILTER ); 555 AttributeValueAssertion assertion = new AttributeValueAssertion(); 556 assertion.setAttributeDesc( ( ( GreaterEqNode<?> ) exprNode ).getAttribute() ); 557 assertion.setAssertionValue( ( ( GreaterEqNode<?> ) exprNode ).getValue() ); 558 ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion ); 559 } 560 else if ( exprNode instanceof LessEqNode<?> ) 561 { 562 filter = new AttributeValueAssertionFilter( LdapConstants.LESS_OR_EQUAL_FILTER ); 563 AttributeValueAssertion assertion = new AttributeValueAssertion(); 564 assertion.setAttributeDesc( ( ( LessEqNode<?> ) exprNode ).getAttribute() ); 565 assertion.setAssertionValue( ( ( LessEqNode<?> ) exprNode ).getValue() ); 566 ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion ); 567 } 568 else if ( exprNode instanceof ApproximateNode<?> ) 569 { 570 filter = new AttributeValueAssertionFilter( LdapConstants.APPROX_MATCH_FILTER ); 571 AttributeValueAssertion assertion = new AttributeValueAssertion(); 572 assertion.setAttributeDesc( ( ( ApproximateNode<?> ) exprNode ).getAttribute() ); 573 assertion.setAssertionValue( ( ( ApproximateNode<?> ) exprNode ).getValue() ); 574 ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion ); 575 } 576 } 577 else if ( exprNode instanceof SubstringNode ) 578 { 579 // Transform Substring Nodes 580 filter = new SubstringFilter(); 581 582 ( ( SubstringFilter ) filter ).setType( ( ( SubstringNode ) exprNode ).getAttribute() ); 583 String initialString = ( ( SubstringNode ) exprNode ).getInitial(); 584 String finalString = ( ( SubstringNode ) exprNode ).getFinal(); 585 List<String> anyStrings = ( ( SubstringNode ) exprNode ).getAny(); 586 587 if ( initialString != null ) 588 { 589 ( ( SubstringFilter ) filter ).setInitialSubstrings( initialString ); 590 } 591 592 if ( finalString != null ) 593 { 594 ( ( SubstringFilter ) filter ).setFinalSubstrings( finalString ); 595 } 596 597 if ( anyStrings != null ) 598 { 599 for ( String any : anyStrings ) 600 { 601 ( ( SubstringFilter ) filter ).addAnySubstrings( any ); 602 } 603 } 604 } 605 else if ( exprNode instanceof ExtensibleNode ) 606 { 607 // Transform Extensible Node 608 filter = new ExtensibleMatchFilter(); 609 610 String attribute = ( ( ExtensibleNode ) exprNode ).getAttribute(); 611 String matchingRule = ( ( ExtensibleNode ) exprNode ).getMatchingRuleId(); 612 boolean dnAttributes = ( ( ExtensibleNode ) exprNode ).hasDnAttributes(); 613 Value<?> value = ( ( ExtensibleNode ) exprNode ).getValue(); 614 615 if ( attribute != null ) 616 { 617 ( ( ExtensibleMatchFilter ) filter ).setType( attribute ); 618 } 619 620 if ( matchingRule != null ) 621 { 622 ( ( ExtensibleMatchFilter ) filter ).setMatchingRule( matchingRule ); 623 } 624 625 ( ( ExtensibleMatchFilter ) filter ).setMatchValue( value ); 626 ( ( ExtensibleMatchFilter ) filter ).setDnAttributes( dnAttributes ); 627 } 628 } 629 630 return filter; 631 } 632 else 633 { 634 // We have found nothing to transform. Return null then. 635 return null; 636 } 637 } 638 639 640 /** 641 * @see Object#hashCode() 642 */ 643 @Override 644 public int hashCode() 645 { 646 int hash = 37; 647 648 if ( getDecorated().getBase() != null ) 649 { 650 hash = hash * 17 + getDecorated().getBase().hashCode(); 651 } 652 653 hash = hash * 17 + getDecorated().getDerefAliases().hashCode(); 654 hash = hash * 17 + getDecorated().getScope().hashCode(); 655 hash = hash * 17 + Long.valueOf( getDecorated().getSizeLimit() ).hashCode(); 656 hash = hash * 17 + getDecorated().getTimeLimit(); 657 hash = hash * 17 + ( getDecorated().getTypesOnly() ? 0 : 1 ); 658 659 List<String> attributes = getDecorated().getAttributes(); 660 if ( attributes != null ) 661 { 662 hash = hash * 17 + attributes.size(); 663 664 // Order doesn't matter, thus just add hashCode 665 for ( String attr : attributes ) 666 { 667 hash = hash + attr.hashCode(); 668 } 669 } 670 671 BranchNormalizedVisitor visitor = new BranchNormalizedVisitor(); 672 getDecorated().getFilter().accept( visitor ); 673 hash = hash * 17 + currentFilter.toString().hashCode(); 674 hash = hash * 17 + super.hashCode(); 675 676 return hash; 677 } 678 679 680 /** 681 * @see Object#equals(Object) 682 */ 683 @Override 684 public boolean equals( Object o ) 685 { 686 if ( !super.equals( o ) ) 687 { 688 return false; 689 } 690 691 if ( ( o == null ) || ( o instanceof SearchRequestDecorator ) ) 692 { 693 return false; 694 } 695 696 SearchRequestDecorator otherSearchRequestDecorator = ( SearchRequestDecorator ) o; 697 698 if ( ( getDecorated() != null ) && ( !getDecorated().equals( otherSearchRequestDecorator.getDecorated() ) ) ) 699 { 700 return false; 701 } 702 703 if ( searchRequestLength != otherSearchRequestDecorator.searchRequestLength ) 704 { 705 return false; 706 } 707 708 if ( attributeDescriptionListLength != otherSearchRequestDecorator.attributeDescriptionListLength ) 709 { 710 return false; 711 } 712 713 if ( ( terminalFilter != null ) && ( terminalFilter.equals( otherSearchRequestDecorator.terminalFilter ) ) ) 714 { 715 return false; 716 } 717 718 if ( ( currentFilter != null ) && ( currentFilter.equals( otherSearchRequestDecorator.currentFilter ) ) ) 719 { 720 return false; 721 } 722 723 if ( ( topFilter != null ) && ( topFilter.equals( otherSearchRequestDecorator.topFilter ) ) ) 724 { 725 return false; 726 } 727 728 if ( tlvId != otherSearchRequestDecorator.tlvId ) 729 { 730 return false; 731 } 732 733 return true; 734 } 735 736 737 //------------------------------------------------------------------------- 738 // The SearchRequest methods 739 //------------------------------------------------------------------------- 740 /** 741 * {@inheritDoc} 742 */ 743 public MessageTypeEnum[] getResponseTypes() 744 { 745 return getDecorated().getResponseTypes(); 746 } 747 748 749 /** 750 * {@inheritDoc} 751 */ 752 public Dn getBase() 753 { 754 return getDecorated().getBase(); 755 } 756 757 758 /** 759 * {@inheritDoc} 760 */ 761 public SearchRequest setBase( Dn baseDn ) 762 { 763 getDecorated().setBase( baseDn ); 764 765 return this; 766 } 767 768 769 /** 770 * {@inheritDoc} 771 */ 772 public SearchScope getScope() 773 { 774 return getDecorated().getScope(); 775 } 776 777 778 /** 779 * {@inheritDoc} 780 */ 781 public SearchRequest setScope( SearchScope scope ) 782 { 783 getDecorated().setScope( scope ); 784 785 return this; 786 } 787 788 789 /** 790 * {@inheritDoc} 791 */ 792 public AliasDerefMode getDerefAliases() 793 { 794 return getDecorated().getDerefAliases(); 795 } 796 797 798 /** 799 * {@inheritDoc} 800 */ 801 public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases ) 802 { 803 getDecorated().setDerefAliases( aliasDerefAliases ); 804 805 return this; 806 } 807 808 809 /** 810 * {@inheritDoc} 811 */ 812 public long getSizeLimit() 813 { 814 return getDecorated().getSizeLimit(); 815 } 816 817 818 /** 819 * {@inheritDoc} 820 */ 821 public SearchRequest setSizeLimit( long entriesMax ) 822 { 823 getDecorated().setSizeLimit( entriesMax ); 824 825 return this; 826 } 827 828 829 /** 830 * {@inheritDoc} 831 */ 832 public int getTimeLimit() 833 { 834 return getDecorated().getTimeLimit(); 835 } 836 837 838 /** 839 * {@inheritDoc} 840 */ 841 public SearchRequest setTimeLimit( int secondsMax ) 842 { 843 getDecorated().setTimeLimit( secondsMax ); 844 845 return this; 846 } 847 848 849 /** 850 * {@inheritDoc} 851 */ 852 public boolean getTypesOnly() 853 { 854 return getDecorated().getTypesOnly(); 855 } 856 857 858 /** 859 * {@inheritDoc} 860 */ 861 public SearchRequest setTypesOnly( boolean typesOnly ) 862 { 863 getDecorated().setTypesOnly( typesOnly ); 864 865 return this; 866 } 867 868 869 /** 870 * {@inheritDoc} 871 */ 872 public ExprNode getFilter() 873 { 874 return getDecorated().getFilter(); 875 } 876 877 878 /** 879 * {@inheritDoc} 880 */ 881 public List<String> getAttributes() 882 { 883 return getDecorated().getAttributes(); 884 } 885 886 887 /** 888 * {@inheritDoc} 889 */ 890 public SearchRequest addAttributes( String... attributes ) 891 { 892 getDecorated().addAttributes( attributes ); 893 894 return this; 895 } 896 897 898 /** 899 * {@inheritDoc} 900 */ 901 public SearchRequest removeAttribute( String attribute ) 902 { 903 getDecorated().removeAttribute( attribute ); 904 905 return this; 906 } 907 908 909 //------------------------------------------------------------------------- 910 // The Decorator methods 911 //------------------------------------------------------------------------- 912 913 /** 914 * Compute the SearchRequest length 915 * 916 * SearchRequest : 917 * <pre> 918 * 0x63 L1 919 * | 920 * +--> 0x04 L2 baseObject 921 * +--> 0x0A 0x01 scope 922 * +--> 0x0A 0x01 derefAliases 923 * +--> 0x02 0x0(1..4) sizeLimit 924 * +--> 0x02 0x0(1..4) timeLimit 925 * +--> 0x01 0x01 typesOnly 926 * +--> filter.computeLength() 927 * +--> 0x30 L3 (Attribute description list) 928 * | 929 * +--> 0x04 L4-1 Attribute description 930 * +--> 0x04 L4-2 Attribute description 931 * +--> ... 932 * +--> 0x04 L4-i Attribute description 933 * +--> ... 934 * +--> 0x04 L4-n Attribute description 935 * </pre> 936 */ 937 public int computeLength() 938 { 939 int searchRequestLength = 0; 940 941 // The baseObject 942 searchRequestLength += 1 + TLV.getNbBytes( Dn.getNbBytes( getBase() ) ) + Dn.getNbBytes( getBase() ); 943 944 // The scope 945 searchRequestLength += 1 + 1 + 1; 946 947 // The derefAliases 948 searchRequestLength += 1 + 1 + 1; 949 950 // The sizeLimit 951 searchRequestLength += 1 + 1 + org.apache.directory.shared.asn1.ber.tlv.Value.getNbBytes( getSizeLimit() ); 952 953 // The timeLimit 954 searchRequestLength += 1 + 1 + org.apache.directory.shared.asn1.ber.tlv.Value.getNbBytes( getTimeLimit() ); 955 956 // The typesOnly 957 searchRequestLength += 1 + 1 + 1; 958 959 // The filter 960 setFilter( getFilter() ); 961 searchRequestLength += 962 getCodecFilter().computeLength(); 963 964 // The attributes description list 965 int attributeDescriptionListLength = 0; 966 967 if ( ( getAttributes() != null ) && ( getAttributes().size() != 0 ) ) 968 { 969 // Compute the attributes length 970 for ( String attribute : getAttributes() ) 971 { 972 // add the attribute length to the attributes length 973 int idLength = Strings.getBytesUtf8( attribute ).length; 974 attributeDescriptionListLength += 1 + TLV.getNbBytes( idLength ) + idLength; 975 } 976 } 977 978 setAttributeDescriptionListLength( attributeDescriptionListLength ); 979 980 searchRequestLength += 1 + TLV.getNbBytes( attributeDescriptionListLength ) + attributeDescriptionListLength; 981 982 setSearchRequestLength( searchRequestLength ); 983 // Return the result. 984 return 1 + TLV.getNbBytes( searchRequestLength ) + searchRequestLength; 985 } 986 987 988 /** 989 * Encode the SearchRequest message to a PDU. 990 * 991 * SearchRequest : 992 * <pre> 993 * 0x63 LL 994 * 0x04 LL baseObject 995 * 0x0A 01 scope 996 * 0x0A 01 derefAliases 997 * 0x02 0N sizeLimit 998 * 0x02 0N timeLimit 999 * 0x01 0x01 typesOnly 1000 * filter.encode() 1001 * 0x30 LL attributeDescriptionList 1002 * 0x04 LL attributeDescription 1003 * ... 1004 * 0x04 LL attributeDescription 1005 * </pre> 1006 * @param buffer The buffer where to put the PDU 1007 * @return The PDU. 1008 */ 1009 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 1010 { 1011 try 1012 { 1013 // The SearchRequest Tag 1014 buffer.put( LdapConstants.SEARCH_REQUEST_TAG ); 1015 buffer.put( TLV.getBytes( getSearchRequestLength() ) ); 1016 1017 // The baseObject 1018 org.apache.directory.shared.asn1.ber.tlv.Value.encode( buffer, Dn.getBytes( getBase() ) ); 1019 1020 // The scope 1021 org.apache.directory.shared.asn1.ber.tlv.Value.encodeEnumerated( buffer, getScope().getScope() ); 1022 1023 // The derefAliases 1024 org.apache.directory.shared.asn1.ber.tlv.Value.encodeEnumerated( buffer, getDerefAliases().getValue() ); 1025 1026 // The sizeLimit 1027 org.apache.directory.shared.asn1.ber.tlv.Value.encode( buffer, getSizeLimit() ); 1028 1029 // The timeLimit 1030 org.apache.directory.shared.asn1.ber.tlv.Value.encode( buffer, getTimeLimit() ); 1031 1032 // The typesOnly 1033 org.apache.directory.shared.asn1.ber.tlv.Value.encode( buffer, getTypesOnly() ); 1034 1035 // The filter 1036 getCodecFilter().encode( buffer ); 1037 1038 // The attributeDescriptionList 1039 buffer.put( UniversalTag.SEQUENCE.getValue() ); 1040 buffer.put( TLV.getBytes( getAttributeDescriptionListLength() ) ); 1041 1042 if ( ( getAttributes() != null ) && ( getAttributes().size() != 0 ) ) 1043 { 1044 // encode each attribute 1045 for ( String attribute : getAttributes() ) 1046 { 1047 org.apache.directory.shared.asn1.ber.tlv.Value.encode( buffer, attribute ); 1048 } 1049 } 1050 } 1051 catch ( BufferOverflowException boe ) 1052 { 1053 throw new EncoderException( I18n.err( I18n.ERR_04005 ) ); 1054 } 1055 1056 return buffer; 1057 } 1058 1059 1060 public SearchResultDone getResultResponse() 1061 { 1062 return getDecorated().getResultResponse(); 1063 } 1064 1065 1066 public boolean hasResponse() 1067 { 1068 return getDecorated().hasResponse(); 1069 } 1070 1071 1072 public void abandon() 1073 { 1074 getDecorated().abandon(); 1075 } 1076 1077 1078 public boolean isAbandoned() 1079 { 1080 return getDecorated().isAbandoned(); 1081 } 1082 1083 1084 public SearchRequest addAbandonListener( AbandonListener listener ) 1085 { 1086 getDecorated().addAbandonListener( listener ); 1087 1088 return this; 1089 } 1090 1091 1092 /** 1093 * {@inheritDoc} 1094 */ 1095 public SearchRequest setMessageId( int messageId ) 1096 { 1097 return (SearchRequest)super.setMessageId( messageId ); 1098 } 1099 1100 1101 /** 1102 * {@inheritDoc} 1103 */ 1104 public SearchRequest addControl( Control control ) throws MessageException 1105 { 1106 return (SearchRequest)super.addControl( control ); 1107 } 1108 1109 1110 /** 1111 * {@inheritDoc} 1112 */ 1113 public SearchRequest addAllControls( Control[] controls ) throws MessageException 1114 { 1115 return (SearchRequest)super.addAllControls( controls ); 1116 } 1117 1118 1119 /** 1120 * {@inheritDoc} 1121 */ 1122 public SearchRequest removeControl( Control control ) throws MessageException 1123 { 1124 return (SearchRequest)super.removeControl( control ); 1125 } 1126}