View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.ldap.codec.decorators;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.directory.api.asn1.DecoderException;
29  import org.apache.directory.api.asn1.EncoderException;
30  import org.apache.directory.api.asn1.ber.Asn1Container;
31  import org.apache.directory.api.asn1.ber.tlv.BerValue;
32  import org.apache.directory.api.asn1.ber.tlv.TLV;
33  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
34  import org.apache.directory.api.i18n.I18n;
35  import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
36  import org.apache.directory.api.ldap.codec.api.LdapApiService;
37  import org.apache.directory.api.ldap.codec.api.LdapConstants;
38  import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
39  import org.apache.directory.api.ldap.codec.api.MessageDecorator;
40  import org.apache.directory.api.ldap.codec.search.AndFilter;
41  import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
42  import org.apache.directory.api.ldap.codec.search.ConnectorFilter;
43  import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
44  import org.apache.directory.api.ldap.codec.search.Filter;
45  import org.apache.directory.api.ldap.codec.search.NotFilter;
46  import org.apache.directory.api.ldap.codec.search.OrFilter;
47  import org.apache.directory.api.ldap.codec.search.PresentFilter;
48  import org.apache.directory.api.ldap.codec.search.SubstringFilter;
49  import org.apache.directory.api.ldap.model.entry.Value;
50  import org.apache.directory.api.ldap.model.exception.LdapException;
51  import org.apache.directory.api.ldap.model.filter.AndNode;
52  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
53  import org.apache.directory.api.ldap.model.filter.BranchNode;
54  import org.apache.directory.api.ldap.model.filter.BranchNormalizedVisitor;
55  import org.apache.directory.api.ldap.model.filter.EqualityNode;
56  import org.apache.directory.api.ldap.model.filter.ExprNode;
57  import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
58  import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
59  import org.apache.directory.api.ldap.model.filter.LeafNode;
60  import org.apache.directory.api.ldap.model.filter.LessEqNode;
61  import org.apache.directory.api.ldap.model.filter.NotNode;
62  import org.apache.directory.api.ldap.model.filter.OrNode;
63  import org.apache.directory.api.ldap.model.filter.PresenceNode;
64  import org.apache.directory.api.ldap.model.filter.SimpleNode;
65  import org.apache.directory.api.ldap.model.filter.SubstringNode;
66  import org.apache.directory.api.ldap.model.message.AbandonListener;
67  import org.apache.directory.api.ldap.model.message.AliasDerefMode;
68  import org.apache.directory.api.ldap.model.message.Control;
69  import org.apache.directory.api.ldap.model.message.Message;
70  import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
71  import org.apache.directory.api.ldap.model.message.SearchRequest;
72  import org.apache.directory.api.ldap.model.message.SearchResultDone;
73  import org.apache.directory.api.ldap.model.message.SearchScope;
74  import org.apache.directory.api.ldap.model.name.Dn;
75  import org.apache.directory.api.util.Strings;
76  
77  
78  /**
79   * A decorator for the SearchRequest message
80   *
81   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
82   */
83  public class SearchRequestDecorator extends MessageDecorator<SearchRequest> implements SearchRequest
84  {
85      /** The searchRequest length */
86      private int searchRequestLength;
87  
88      /** The attributeDescriptionList length */
89      private int attributeDescriptionListLength;
90  
91      /** A temporary storage for a terminal Filter */
92      private Filter terminalFilter;
93  
94      /** The current filter. This is used while decoding a PDU */
95      private Filter currentFilter;
96  
97      /** The global filter. This is used while decoding a PDU */
98      private Filter topFilter;
99  
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 }