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