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}