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