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.model.message;
21  
22  
23  import java.text.ParseException;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.List;
28  
29  import org.apache.directory.api.ldap.model.exception.LdapException;
30  import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
31  import org.apache.directory.api.ldap.model.filter.BranchNormalizedVisitor;
32  import org.apache.directory.api.ldap.model.filter.ExprNode;
33  import org.apache.directory.api.ldap.model.filter.FilterParser;
34  import org.apache.directory.api.ldap.model.name.Dn;
35  import org.apache.directory.api.util.Strings;
36  
37  
38  /**
39   * SearchRequest implementation.
40   * 
41   * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
42   */
43  public class SearchRequestImpl extends AbstractAbandonableRequest implements SearchRequest
44  {
45      static final long serialVersionUID = -5655881944020886218L;
46  
47      /** Search base distinguished name */
48      private Dn baseDn;
49  
50      /** Search filter expression tree's root node */
51      private ExprNode filterNode;
52  
53      /** Search scope enumeration value */
54      private SearchScope scope;
55  
56      /** Types only return flag */
57      private boolean typesOnly;
58  
59      /** Max size in entries to return */
60      private long sizeLimit;
61  
62      /** Max seconds to wait for search to complete */
63      private int timeLimit;
64  
65      /** Alias dereferencing mode enumeration value (default to DEREF_ALWAYS) */
66      private AliasDerefMode aliasDerefMode = AliasDerefMode.DEREF_ALWAYS;
67  
68      /** Attributes to return */
69      private List<String> attributes = new ArrayList<String>();
70  
71      /** The final result containing SearchResponseDone response */
72      private SearchResultDone response;
73  
74      /** A flag set to tell the search what to do wth referrals */
75      private ReferralsPolicyEnum referralHandling = ReferralsPolicyEnum.THROW;
76  
77  
78      // -----------------------------------------------------------------------
79      // Constructors
80      // -----------------------------------------------------------------------
81      /**
82       * Creates a SearcRequest implementing object used to search the
83       * DIT.
84       */
85      public SearchRequestImpl()
86      {
87          super( -1, MessageTypeEnum.SEARCH_REQUEST );
88      }
89  
90  
91      // ------------------------------------------------------------------------
92      // SearchRequest Interface Method Implementations
93      // ------------------------------------------------------------------------
94  
95      /**
96       * {@inheritDoc}
97       */
98      public List<String> getAttributes()
99      {
100         return Collections.unmodifiableList( attributes );
101     }
102 
103 
104     /**
105      * Gets the search base as a distinguished name.
106      * 
107      * @return the search base
108      */
109     public Dn getBase()
110     {
111         return baseDn;
112     }
113 
114 
115     /**
116      * {@inheritDoc}
117      */
118     public SearchRequest setBase( Dn base )
119     {
120         baseDn = base;
121 
122         return this;
123     }
124 
125 
126     /**
127      * {@inheritDoc}
128      */
129     public AliasDerefMode getDerefAliases()
130     {
131         return aliasDerefMode;
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
139     {
140         this.aliasDerefMode = aliasDerefAliases;
141 
142         return this;
143     }
144 
145 
146     /**
147      * {@inheritDoc}
148      */
149     public ExprNode getFilter()
150     {
151         return filterNode;
152     }
153 
154 
155     /**
156      * {@inheritDoc}
157      */
158     public SearchRequest setFilter( ExprNode filter )
159     {
160         this.filterNode = filter;
161         return this;
162     }
163 
164 
165     /**
166      * {@inheritDoc}
167      */
168     public SearchRequest setFilter( String filter ) throws LdapException
169     {
170         try
171         {
172             filterNode = FilterParser.parse( Strings.getBytesUtf8( filter ) );
173         }
174         catch ( ParseException pe )
175         {
176             String msg = "The filter " + filter + " is invalid.";
177             throw new LdapProtocolErrorException( msg, pe );
178         }
179 
180         return this;
181     }
182 
183 
184     /**
185      * {@inheritDoc}
186      */
187     public MessageTypeEnum[] getResponseTypes()
188     {
189         return RESPONSE_TYPES.clone();
190     }
191 
192 
193     /**
194      * {@inheritDoc}
195      */
196     public SearchScope getScope()
197     {
198         return scope;
199     }
200 
201 
202     /**
203      * {@inheritDoc}
204      */
205     public SearchRequest setScope( SearchScope scope )
206     {
207         this.scope = scope;
208 
209         return this;
210     }
211 
212 
213     /**
214      * {@inheritDoc}
215      */
216     public long getSizeLimit()
217     {
218         return sizeLimit;
219     }
220 
221 
222     /**
223      * {@inheritDoc}
224      */
225     public SearchRequest setSizeLimit( long entriesMax )
226     {
227         sizeLimit = entriesMax;
228 
229         return this;
230     }
231 
232 
233     /**
234      * {@inheritDoc}
235      */
236     public int getTimeLimit()
237     {
238         return timeLimit;
239     }
240 
241 
242     /**
243      * {@inheritDoc}
244      */
245     public SearchRequest setTimeLimit( int secondsMax )
246     {
247         timeLimit = secondsMax;
248 
249         return this;
250     }
251 
252 
253     /**
254      * {@inheritDoc}
255      */
256     public boolean getTypesOnly()
257     {
258         return typesOnly;
259     }
260 
261 
262     /**
263      * {@inheritDoc}
264      */
265     public SearchRequest setTypesOnly( boolean typesOnly )
266     {
267         this.typesOnly = typesOnly;
268 
269         return this;
270     }
271 
272 
273     /**
274      * {@inheritDoc}
275      */
276     public SearchRequest addAttributes( String... attributesToAdd )
277     {
278         this.attributes.addAll( Arrays.asList( attributesToAdd ) );
279 
280         return this;
281     }
282 
283 
284     /**
285      * {@inheritDoc}
286      */
287     public SearchRequest removeAttribute( String attribute )
288     {
289         attributes.remove( attribute );
290 
291         return this;
292     }
293 
294 
295     /**
296      * {@inheritDoc}
297      */
298     public SearchResultDone getResultResponse()
299     {
300         if ( response == null )
301         {
302             response = new SearchResultDoneImpl( getMessageId() );
303         }
304 
305         return response;
306     }
307 
308 
309     /**
310      * {@inheritDoc}
311      */
312     public SearchRequest setMessageId( int messageId )
313     {
314         super.setMessageId( messageId );
315 
316         return this;
317     }
318 
319 
320     /**
321      * {@inheritDoc}
322      */
323     public SearchRequest addControl( Control control )
324     {
325         return ( SearchRequest ) super.addControl( control );
326     }
327 
328 
329     /**
330      * {@inheritDoc}
331      */
332     public SearchRequest addAllControls( Control[] controls )
333     {
334         return ( SearchRequest ) super.addAllControls( controls );
335     }
336 
337 
338     /**
339      * {@inheritDoc}
340      */
341     public SearchRequest removeControl( Control control )
342     {
343         return ( SearchRequest ) super.removeControl( control );
344     }
345 
346 
347     /**
348      * {@inheritDoc}
349      */
350     @Override
351     public int hashCode()
352     {
353         int hash = 37;
354 
355         if ( baseDn != null )
356         {
357             hash = hash * 17 + baseDn.hashCode();
358         }
359 
360         hash = hash * 17 + aliasDerefMode.hashCode();
361         hash = hash * 17 + scope.hashCode();
362         hash = hash * 17 + Long.valueOf( sizeLimit ).hashCode();
363         hash = hash * 17 + timeLimit;
364         hash = hash * 17 + ( typesOnly ? 0 : 1 );
365 
366         if ( attributes != null )
367         {
368             hash = hash * 17 + attributes.size();
369 
370             // Order doesn't matter, thus just add hashCode
371             for ( String attr : attributes )
372             {
373                 if ( attr != null )
374                 {
375                     hash = hash + attr.hashCode();
376                 }
377             }
378         }
379 
380         BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
381         filterNode.accept( visitor );
382         hash = hash * 17 + filterNode.toString().hashCode();
383         hash = hash * 17 + super.hashCode();
384 
385         return hash;
386     }
387 
388 
389     /**
390      * Checks to see if two search requests are equal. The Lockable properties
391      * and the get/set context specific parameters are not consulted to
392      * determine equality. The filter expression tree comparison will normalize
393      * the child order of filter branch nodes then generate a string
394      * representation which is comparable. For the time being this is a very
395      * costly operation.
396      * 
397      * @param obj the object to check for equality to this SearchRequest
398      * @return true if the obj is a SearchRequest and equals this SearchRequest,
399      *         false otherwise
400      */
401     public boolean equals( Object obj )
402     {
403         if ( obj == this )
404         {
405             return true;
406         }
407 
408         if ( !super.equals( obj ) )
409         {
410             return false;
411         }
412 
413         SearchRequest req = ( SearchRequest ) obj;
414 
415         if ( !req.getBase().equals( baseDn ) )
416         {
417             return false;
418         }
419 
420         if ( req.getDerefAliases() != aliasDerefMode )
421         {
422             return false;
423         }
424 
425         if ( req.getScope() != scope )
426         {
427             return false;
428         }
429 
430         if ( req.getSizeLimit() != sizeLimit )
431         {
432             return false;
433         }
434 
435         if ( req.getTimeLimit() != timeLimit )
436         {
437             return false;
438         }
439 
440         if ( req.getTypesOnly() != typesOnly )
441         {
442             return false;
443         }
444 
445         if ( req.getAttributes() == null && attributes != null && attributes.size() > 0 )
446         {
447             return false;
448         }
449 
450         if ( req.getAttributes() != null && attributes == null && req.getAttributes().size() > 0 )
451         {
452             return false;
453         }
454 
455         if ( req.getAttributes() != null && attributes != null )
456         {
457             if ( req.getAttributes().size() != attributes.size() )
458             {
459                 return false;
460             }
461 
462             for ( String attribute : attributes )
463             {
464                 if ( !req.getAttributes().contains( attribute ) )
465                 {
466                     return false;
467                 }
468             }
469         }
470 
471         BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
472         req.getFilter().accept( visitor );
473         filterNode.accept( visitor );
474 
475         String myFilterString = filterNode.toString();
476         String reqFilterString = req.getFilter().toString();
477 
478         return myFilterString.equals( reqFilterString );
479     }
480 
481 
482     /**
483      * Return a string the represent a SearchRequest
484      * {@inheritDoc}
485      */
486     public String toString()
487     {
488         StringBuilder sb = new StringBuilder();
489 
490         sb.append( "    SearchRequest\n" );
491         sb.append( "        baseDn : '" ).append( baseDn ).append( "'\n" );
492 
493         if ( filterNode != null )
494         {
495             sb.append( "        filter : '" );
496             sb.append( filterNode.toString() );
497             sb.append( "'\n" );
498         }
499 
500         sb.append( "        scope : " );
501 
502         switch ( scope )
503         {
504             case OBJECT:
505                 sb.append( "base object" );
506                 break;
507 
508             case ONELEVEL:
509                 sb.append( "single level" );
510                 break;
511 
512             case SUBTREE:
513                 sb.append( "whole subtree" );
514                 break;
515         }
516 
517         sb.append( '\n' );
518 
519         sb.append( "        typesOnly : " ).append( typesOnly ).append( '\n' );
520 
521         sb.append( "        Size Limit : " );
522 
523         if ( sizeLimit == 0L )
524         {
525             sb.append( "no limit" );
526         }
527         else
528         {
529             sb.append( sizeLimit );
530         }
531 
532         sb.append( '\n' );
533 
534         sb.append( "        Time Limit : " );
535 
536         if ( timeLimit == 0 )
537         {
538             sb.append( "no limit" );
539         }
540         else
541         {
542             sb.append( timeLimit );
543         }
544 
545         sb.append( '\n' );
546 
547         sb.append( "        Deref Aliases : " );
548 
549         switch ( aliasDerefMode )
550         {
551             case NEVER_DEREF_ALIASES:
552                 sb.append( "never Deref Aliases" );
553                 break;
554 
555             case DEREF_IN_SEARCHING:
556                 sb.append( "deref In Searching" );
557                 break;
558 
559             case DEREF_FINDING_BASE_OBJ:
560                 sb.append( "deref Finding Base Obj" );
561                 break;
562 
563             case DEREF_ALWAYS:
564                 sb.append( "deref Always" );
565                 break;
566         }
567 
568         sb.append( '\n' );
569         sb.append( "        attributes : " );
570 
571         boolean isFirst = true;
572 
573         if ( attributes != null )
574         {
575             for ( String attribute : attributes )
576             {
577                 if ( isFirst )
578                 {
579                     isFirst = false;
580                 }
581                 else
582                 {
583                     sb.append( ", " );
584                 }
585 
586                 sb.append( '\'' ).append( attribute ).append( '\'' );
587             }
588         }
589 
590         sb.append( '\n' );
591 
592         // The controls
593         sb.append( super.toString() );
594 
595         return super.toString( sb.toString() );
596     }
597 
598 
599     /**
600      * {@inheritDoc}
601      */
602     public boolean isFollowReferrals()
603     {
604         return referralHandling == ReferralsPolicyEnum.FOLLOW;
605     }
606 
607 
608     /**
609      * {@inheritDoc}
610      */
611     public SearchRequest followReferrals()
612     {
613         referralHandling = ReferralsPolicyEnum.FOLLOW;
614 
615         return this;
616     }
617 
618 
619     /**
620      * {@inheritDoc}
621      */
622     public boolean isIgnoreReferrals()
623     {
624         return referralHandling == ReferralsPolicyEnum.IGNORE;
625     }
626 
627 
628     /**
629      * {@inheritDoc}
630      */
631     public SearchRequest ignoreReferrals()
632     {
633         referralHandling = ReferralsPolicyEnum.IGNORE;
634 
635         return this;
636     }
637 }