001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.shared.ldap.model.message; 021 022 023import java.text.ParseException; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.List; 028 029import org.apache.directory.shared.ldap.model.exception.LdapException; 030import org.apache.directory.shared.ldap.model.exception.LdapProtocolErrorException; 031import org.apache.directory.shared.ldap.model.exception.MessageException; 032import org.apache.directory.shared.ldap.model.filter.BranchNormalizedVisitor; 033import org.apache.directory.shared.ldap.model.filter.ExprNode; 034import org.apache.directory.shared.ldap.model.filter.FilterParser; 035import org.apache.directory.shared.ldap.model.name.Dn; 036 037 038/** 039 * SearchRequest implementation. 040 * 041 * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a> 042 */ 043public class SearchRequestImpl extends AbstractAbandonableRequest implements SearchRequest 044{ 045 static final long serialVersionUID = -5655881944020886218L; 046 047 /** Search base distinguished name */ 048 private Dn baseDn; 049 050 /** Search filter expression tree's root node */ 051 private ExprNode filterNode; 052 053 /** Search scope enumeration value */ 054 private SearchScope scope; 055 056 /** Types only return flag */ 057 private boolean typesOnly; 058 059 /** Max size in entries to return */ 060 private long sizeLimit; 061 062 /** Max seconds to wait for search to complete */ 063 private int timeLimit; 064 065 /** Alias dereferencing mode enumeration value (default to DEREF_ALWAYS) */ 066 private AliasDerefMode aliasDerefMode = AliasDerefMode.DEREF_ALWAYS; 067 068 /** Attributes to return */ 069 private List<String> attributes = new ArrayList<String>(); 070 071 /** The final result containing SearchResponseDone response */ 072 private SearchResultDone response; 073 074 075 // ----------------------------------------------------------------------- 076 // Constructors 077 // ----------------------------------------------------------------------- 078 /** 079 * Creates a SearcRequest implementing object used to search the 080 * DIT. 081 */ 082 public SearchRequestImpl() 083 { 084 super( -1, MessageTypeEnum.SEARCH_REQUEST ); 085 } 086 087 088 // ------------------------------------------------------------------------ 089 // SearchRequest Interface Method Implementations 090 // ------------------------------------------------------------------------ 091 092 093 /** 094 * {@inheritDoc} 095 */ 096 public List<String> getAttributes() 097 { 098 return Collections.unmodifiableList( attributes ); 099 } 100 101 102 /** 103 * Gets the search base as a distinguished name. 104 * 105 * @return the search base 106 */ 107 public Dn getBase() 108 { 109 return baseDn; 110 } 111 112 113 /** 114 * {@inheritDoc} 115 */ 116 public SearchRequest setBase( Dn base ) 117 { 118 baseDn = base; 119 120 return this; 121 } 122 123 124 /** 125 * {@inheritDoc} 126 */ 127 public AliasDerefMode getDerefAliases() 128 { 129 return aliasDerefMode; 130 } 131 132 133 /** 134 * {@inheritDoc} 135 */ 136 public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases ) 137 { 138 this.aliasDerefMode = aliasDerefAliases; 139 140 return this; 141 } 142 143 144 /** 145 * {@inheritDoc} 146 */ 147 public ExprNode getFilter() 148 { 149 return filterNode; 150 } 151 152 153 /** 154 * {@inheritDoc} 155 */ 156 public SearchRequest setFilter( ExprNode filter ) 157 { 158 this.filterNode = filter; 159 return this; 160 } 161 162 163 /** 164 * {@inheritDoc} 165 */ 166 public SearchRequest setFilter( String filter ) throws LdapException 167 { 168 try 169 { 170 filterNode = FilterParser.parse( filter ); 171 } 172 catch ( ParseException pe ) 173 { 174 String msg = "The filter" + filter + " is invalid."; 175 throw new LdapProtocolErrorException( msg, pe ); 176 } 177 178 return this; 179 } 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 public MessageTypeEnum[] getResponseTypes() 186 { 187 return RESPONSE_TYPES.clone(); 188 } 189 190 191 /** 192 * {@inheritDoc} 193 */ 194 public SearchScope getScope() 195 { 196 return scope; 197 } 198 199 200 /** 201 * {@inheritDoc} 202 */ 203 public SearchRequest setScope( SearchScope scope ) 204 { 205 this.scope = scope; 206 207 return this; 208 } 209 210 211 /** 212 * {@inheritDoc} 213 */ 214 public long getSizeLimit() 215 { 216 return sizeLimit; 217 } 218 219 220 /** 221 * {@inheritDoc} 222 */ 223 public SearchRequest setSizeLimit( long entriesMax ) 224 { 225 sizeLimit = entriesMax; 226 227 return this; 228 } 229 230 231 /** 232 * {@inheritDoc} 233 */ 234 public int getTimeLimit() 235 { 236 return timeLimit; 237 } 238 239 240 /** 241 * {@inheritDoc} 242 */ 243 public SearchRequest setTimeLimit( int secondsMax ) 244 { 245 timeLimit = secondsMax; 246 247 return this; 248 } 249 250 251 /** 252 * {@inheritDoc} 253 */ 254 public boolean getTypesOnly() 255 { 256 return typesOnly; 257 } 258 259 260 /** 261 * {@inheritDoc} 262 */ 263 public SearchRequest setTypesOnly( boolean typesOnly ) 264 { 265 this.typesOnly = typesOnly; 266 267 return this; 268 } 269 270 271 /** 272 * {@inheritDoc} 273 */ 274 public SearchRequest addAttributes( String... attributesToAdd ) 275 { 276 this.attributes.addAll( Arrays.asList( attributesToAdd ) ); 277 278 return this; 279 } 280 281 282 /** 283 * {@inheritDoc} 284 */ 285 public SearchRequest removeAttribute( String attribute ) 286 { 287 attributes.remove( attribute ); 288 289 return this; 290 } 291 292 293 /** 294 * {@inheritDoc} 295 */ 296 public SearchResultDone getResultResponse() 297 { 298 if ( response == null ) 299 { 300 response = new SearchResultDoneImpl( getMessageId() ); 301 } 302 303 return response; 304 } 305 306 307 /** 308 * {@inheritDoc} 309 */ 310 public SearchRequest setMessageId( int messageId ) 311 { 312 super.setMessageId( messageId ); 313 314 return this; 315 } 316 317 318 /** 319 * {@inheritDoc} 320 */ 321 public SearchRequest addControl( Control control ) throws MessageException 322 { 323 return (SearchRequest)super.addControl( control ); 324 } 325 326 327 /** 328 * {@inheritDoc} 329 */ 330 public SearchRequest addAllControls( Control[] controls ) throws MessageException 331 { 332 return (SearchRequest)super.addAllControls( controls ); 333 } 334 335 336 /** 337 * {@inheritDoc} 338 */ 339 public SearchRequest removeControl( Control control ) throws MessageException 340 { 341 return (SearchRequest)super.removeControl( control ); 342 } 343 344 345 /** 346 * {@inheritDoc} 347 */ 348 @Override 349 public int hashCode() 350 { 351 int hash = 37; 352 353 if ( baseDn != null ) 354 { 355 hash = hash * 17 + baseDn.hashCode(); 356 } 357 358 hash = hash * 17 + aliasDerefMode.hashCode(); 359 hash = hash * 17 + scope.hashCode(); 360 hash = hash * 17 + Long.valueOf( sizeLimit ).hashCode(); 361 hash = hash * 17 + timeLimit; 362 hash = hash * 17 + ( typesOnly ? 0 : 1 ); 363 364 if ( attributes != null ) 365 { 366 hash = hash * 17 + attributes.size(); 367 368 // Order doesn't matter, thus just add hashCode 369 for ( String attr : attributes ) 370 { 371 hash = hash + attr.hashCode(); 372 } 373 } 374 375 BranchNormalizedVisitor visitor = new BranchNormalizedVisitor(); 376 filterNode.accept( visitor ); 377 hash = hash * 17 + filterNode.toString().hashCode(); 378 hash = hash * 17 + super.hashCode(); 379 380 return hash; 381 } 382 383 384 /** 385 * Checks to see if two search requests are equal. The Lockable properties 386 * and the get/set context specific parameters are not consulted to 387 * determine equality. The filter expression tree comparison will normalize 388 * the child order of filter branch nodes then generate a string 389 * representation which is comparable. For the time being this is a very 390 * costly operation. 391 * 392 * @param obj the object to check for equality to this SearchRequest 393 * @return true if the obj is a SearchRequest and equals this SearchRequest, 394 * false otherwise 395 */ 396 public boolean equals( Object obj ) 397 { 398 if ( obj == this ) 399 { 400 return true; 401 } 402 403 if ( ! super.equals( obj ) ) 404 { 405 return false; 406 } 407 408 SearchRequest req = ( SearchRequest ) obj; 409 410 if ( !req.getBase().equals( baseDn ) ) 411 { 412 return false; 413 } 414 415 if ( req.getDerefAliases() != aliasDerefMode ) 416 { 417 return false; 418 } 419 420 if ( req.getScope() != scope ) 421 { 422 return false; 423 } 424 425 if ( req.getSizeLimit() != sizeLimit ) 426 { 427 return false; 428 } 429 430 if ( req.getTimeLimit() != timeLimit ) 431 { 432 return false; 433 } 434 435 if ( req.getTypesOnly() != typesOnly ) 436 { 437 return false; 438 } 439 440 if ( req.getAttributes() == null && attributes != null && attributes.size() > 0 ) 441 { 442 return false; 443 } 444 445 if ( req.getAttributes() != null && attributes == null && req.getAttributes().size() > 0 ) 446 { 447 return false; 448 } 449 450 if ( req.getAttributes() != null && attributes != null ) 451 { 452 if ( req.getAttributes().size() != attributes.size() ) 453 { 454 return false; 455 } 456 457 for ( String attribute : attributes ) 458 { 459 if ( ! req.getAttributes().contains( attribute ) ) 460 { 461 return false; 462 } 463 } 464 } 465 466 BranchNormalizedVisitor visitor = new BranchNormalizedVisitor(); 467 req.getFilter().accept( visitor ); 468 filterNode.accept( visitor ); 469 470 String myFilterString = filterNode.toString(); 471 String reqFilterString = req.getFilter().toString(); 472 473 return myFilterString.equals( reqFilterString ); 474 } 475 476 477 /** 478 * Return a string the represent a SearchRequest 479 * {@inheritDoc} 480 */ 481 public String toString() 482 { 483 StringBuilder sb = new StringBuilder(); 484 485 sb.append( " SearchRequest\n" ); 486 sb.append( " baseDn : '" ).append( baseDn ).append( "'\n" ); 487 488 if ( filterNode != null ) 489 { 490 sb.append( " filter : '" ); 491 sb.append( filterNode.toString() ); 492 sb.append( "'\n" ); 493 } 494 495 sb.append( " scope : " ); 496 497 switch ( scope ) 498 { 499 case OBJECT: 500 sb.append( "base object" ); 501 break; 502 503 case ONELEVEL: 504 sb.append( "single level" ); 505 break; 506 507 case SUBTREE: 508 sb.append( "whole subtree" ); 509 break; 510 } 511 512 sb.append( '\n' ); 513 514 sb.append( " typesOnly : " ).append( typesOnly ).append( '\n' ); 515 516 sb.append( " Size Limit : " ); 517 518 if ( sizeLimit == 0L ) 519 { 520 sb.append( "no limit" ); 521 } 522 else 523 { 524 sb.append( sizeLimit ); 525 } 526 527 sb.append( '\n' ); 528 529 sb.append( " Time Limit : " ); 530 531 if ( timeLimit == 0 ) 532 { 533 sb.append( "no limit" ); 534 } 535 else 536 { 537 sb.append( timeLimit ); 538 } 539 540 sb.append( '\n' ); 541 542 sb.append( " Deref Aliases : " ); 543 544 switch ( aliasDerefMode ) 545 { 546 case NEVER_DEREF_ALIASES: 547 sb.append( "never Deref Aliases" ); 548 break; 549 550 case DEREF_IN_SEARCHING: 551 sb.append( "deref In Searching" ); 552 break; 553 554 case DEREF_FINDING_BASE_OBJ: 555 sb.append( "deref Finding Base Obj" ); 556 break; 557 558 case DEREF_ALWAYS: 559 sb.append( "deref Always" ); 560 break; 561 } 562 563 sb.append( '\n' ); 564 sb.append( " attributes : " ); 565 566 boolean isFirst = true; 567 568 if ( attributes != null ) 569 { 570 for ( String attribute : attributes ) 571 { 572 if ( isFirst ) 573 { 574 isFirst = false; 575 } 576 else 577 { 578 sb.append(", "); 579 } 580 581 sb.append('\'').append( attribute ).append('\''); 582 } 583 } 584 585 sb.append( '\n' ); 586 587 // The controls 588 sb.append( super.toString() ); 589 590 return super.toString( sb.toString() ); 591 } 592}