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}