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