001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.protocols.ldap; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.ArrayList; 033 import java.util.Iterator; 034 import java.util.LinkedHashSet; 035 036 import org.opends.server.protocols.asn1.ASN1Boolean; 037 import org.opends.server.protocols.asn1.ASN1Element; 038 import org.opends.server.protocols.asn1.ASN1Enumerated; 039 import org.opends.server.protocols.asn1.ASN1Integer; 040 import org.opends.server.protocols.asn1.ASN1OctetString; 041 import org.opends.server.protocols.asn1.ASN1Sequence; 042 import org.opends.server.types.DebugLogLevel; 043 import org.opends.server.types.DereferencePolicy; 044 import org.opends.server.types.LDAPException; 045 import org.opends.server.types.SearchScope; 046 047 import static org.opends.server.loggers.debug.DebugLogger.*; 048 import org.opends.server.loggers.debug.DebugTracer; 049 import static org.opends.messages.ProtocolMessages.*; 050 import static org.opends.server.protocols.ldap.LDAPConstants.*; 051 import static org.opends.server.protocols.ldap.LDAPResultCode.*; 052 import static org.opends.server.util.ServerConstants.*; 053 054 055 056 /** 057 * This class defines the structures and methods for an LDAP search request 058 * protocol op, which is used to locate entries based on a set of criteria. 059 */ 060 public class SearchRequestProtocolOp 061 extends ProtocolOp 062 { 063 /** 064 * The tracer object for the debug logger. 065 */ 066 private static final DebugTracer TRACER = getTracer(); 067 068 // The typesOnly flag for this search request. 069 private boolean typesOnly; 070 071 // The alias dereferencing policy for this search request. 072 private DereferencePolicy dereferencePolicy; 073 074 // The base DN for this search request. 075 private ASN1OctetString baseDN; 076 077 // The size limit for this search request. 078 private int sizeLimit; 079 080 // The time limit for this search request. 081 private int timeLimit; 082 083 // The filter for this search request. 084 private LDAPFilter filter; 085 086 // The set of requested attributes for this search request. 087 private LinkedHashSet<String> attributes; 088 089 // The scope for this search request. 090 private SearchScope scope; 091 092 093 094 /** 095 * Creates a new search request protocol op with the provided information. 096 * 097 * @param baseDN The base DN for this search request. 098 * @param scope The scope for this search request. 099 * @param dereferencePolicy The alias dereferencing policy for this search 100 * request. 101 * @param sizeLimit The size limit for this search request. 102 * @param timeLimit The time limit for this search request. 103 * @param typesOnly The typesOnly flag for this search request. 104 * @param filter The filter for this search request. 105 * @param attributes The set of requested attributes for this search 106 * request. 107 */ 108 public SearchRequestProtocolOp(ASN1OctetString baseDN, SearchScope scope, 109 DereferencePolicy dereferencePolicy, 110 int sizeLimit, int timeLimit, 111 boolean typesOnly, LDAPFilter filter, 112 LinkedHashSet<String> attributes) 113 { 114 this.baseDN = baseDN; 115 this.scope = scope; 116 this.dereferencePolicy = dereferencePolicy; 117 this.sizeLimit = sizeLimit; 118 this.timeLimit = timeLimit; 119 this.typesOnly = typesOnly; 120 this.filter = filter; 121 122 if (attributes == null) 123 { 124 this.attributes = new LinkedHashSet<String>(0); 125 } 126 else 127 { 128 this.attributes = attributes; 129 } 130 } 131 132 133 134 /** 135 * Retrieves the base DN for this search request. 136 * 137 * @return The base DN for this search request. 138 */ 139 public ASN1OctetString getBaseDN() 140 { 141 return baseDN; 142 } 143 144 145 146 /** 147 * Specifies the base DN for this search request. 148 * 149 * @param baseDN The base DN for this search request. 150 */ 151 public void setBaseDN(ASN1OctetString baseDN) 152 { 153 this.baseDN = baseDN; 154 } 155 156 157 158 /** 159 * Retrieves the scope for this search request. 160 * 161 * @return The scope for this search request. 162 */ 163 public SearchScope getScope() 164 { 165 return scope; 166 } 167 168 169 170 /** 171 * Specifies the scope for this search request. 172 * 173 * @param scope The scope for this search request. 174 */ 175 public void setScope(SearchScope scope) 176 { 177 this.scope = scope; 178 } 179 180 181 182 /** 183 * Retrieves the alias dereferencing policy for this search request. 184 * 185 * @return The alias dereferencing policy for this search request. 186 */ 187 public DereferencePolicy getDereferencePolicy() 188 { 189 return dereferencePolicy; 190 } 191 192 193 194 /** 195 * Specifies the alias dereferencing policy for this search request. 196 * 197 * @param dereferencePolicy The alias dereferencing policy for this search 198 * request. 199 */ 200 public void setDereferencePolicy(DereferencePolicy dereferencePolicy) 201 { 202 this.dereferencePolicy = dereferencePolicy; 203 } 204 205 206 207 /** 208 * Retrieves the size limit for this search request. 209 * 210 * @return The size limit for this search request. 211 */ 212 public int getSizeLimit() 213 { 214 return sizeLimit; 215 } 216 217 218 219 /** 220 * Specifies the size limit for this search request. 221 * 222 * @param sizeLimit The size limit for this search request. 223 */ 224 public void setSizeLimit(int sizeLimit) 225 { 226 this.sizeLimit = sizeLimit; 227 } 228 229 230 231 /** 232 * Retrieves the time limit for this search request. 233 * 234 * @return The time limit for this search request. 235 */ 236 public int getTimeLimit() 237 { 238 return timeLimit; 239 } 240 241 242 243 /** 244 * Specifies the time limit for this search request. 245 * 246 * @param timeLimit The time limit for this search request. 247 */ 248 public void setTimeLimit(int timeLimit) 249 { 250 this.timeLimit = timeLimit; 251 } 252 253 254 255 /** 256 * Retrieves the value of the typesOnly flag for this search request. 257 * 258 * @return The value of tye typesOnly flag for this search request. 259 */ 260 public boolean getTypesOnly() 261 { 262 return typesOnly; 263 } 264 265 266 267 /** 268 * Specifies the value of the typesOnly flag for this search request. 269 * 270 * @param typesOnly The value of the typesOnly flag for this search request. 271 */ 272 public void setTypesOnly(boolean typesOnly) 273 { 274 this.typesOnly = typesOnly; 275 } 276 277 278 279 /** 280 * Retrieves the filter for this search request. 281 * 282 * @return The filter for this search request. 283 */ 284 public LDAPFilter getFilter() 285 { 286 return filter; 287 } 288 289 290 291 /** 292 * Specifies the filter for this search request. 293 * 294 * @param filter The filter for this search request. 295 */ 296 public void setFilter(LDAPFilter filter) 297 { 298 this.filter = filter; 299 } 300 301 302 303 /** 304 * Retrieves the set of requested attributes for this search request. The 305 * returned list may be modified by the caller. 306 * 307 * @return The set of requested attributes for this search request. 308 */ 309 public LinkedHashSet<String> getAttributes() 310 { 311 return attributes; 312 } 313 314 315 316 /** 317 * Specifies the set of requested attributes for this search request. 318 * 319 * @param attributes The set of requested attributes for this search 320 * request. 321 */ 322 public void setAttributes(LinkedHashSet<String> attributes) 323 { 324 if (attributes == null) 325 { 326 this.attributes.clear(); 327 } 328 else 329 { 330 this.attributes = attributes; 331 } 332 } 333 334 335 336 /** 337 * Retrieves the BER type for this protocol op. 338 * 339 * @return The BER type for this protocol op. 340 */ 341 public byte getType() 342 { 343 return OP_TYPE_SEARCH_REQUEST; 344 } 345 346 347 348 /** 349 * Retrieves the name for this protocol op type. 350 * 351 * @return The name for this protocol op type. 352 */ 353 public String getProtocolOpName() 354 { 355 return "Search Request"; 356 } 357 358 359 360 /** 361 * Encodes this protocol op to an ASN.1 element suitable for including in an 362 * LDAP message. 363 * 364 * @return The ASN.1 element containing the encoded protocol op. 365 */ 366 public ASN1Element encode() 367 { 368 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(8); 369 elements.add(baseDN); 370 elements.add(new ASN1Enumerated(scope.intValue())); 371 elements.add(new ASN1Enumerated(dereferencePolicy.intValue())); 372 elements.add(new ASN1Integer(sizeLimit)); 373 elements.add(new ASN1Integer(timeLimit)); 374 elements.add(new ASN1Boolean(typesOnly)); 375 elements.add(filter.encode()); 376 377 ArrayList<ASN1Element> attrElements = 378 new ArrayList<ASN1Element>(attributes.size()); 379 for (String attribute : attributes) 380 { 381 attrElements.add(new ASN1OctetString(attribute)); 382 } 383 elements.add(new ASN1Sequence(attrElements)); 384 385 return new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements); 386 } 387 388 389 390 /** 391 * Decodes the provided ASN.1 element as an LDAP search request protocol op. 392 * 393 * @param element The ASN.1 element to decode. 394 * 395 * @return The decoded LDAP search request protocol op. 396 * 397 * @throws LDAPException If a problem occurs while decoding the provided 398 * ASN.1 element as an LDAP search request protocol 399 * op. 400 */ 401 public static SearchRequestProtocolOp decodeSearchRequest(ASN1Element element) 402 throws LDAPException 403 { 404 ArrayList<ASN1Element> elements; 405 try 406 { 407 elements = element.decodeAsSequence().elements(); 408 } 409 catch (Exception e) 410 { 411 if (debugEnabled()) 412 { 413 TRACER.debugCaught(DebugLogLevel.ERROR, e); 414 } 415 416 Message message = 417 ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e)); 418 throw new LDAPException(PROTOCOL_ERROR, message, e); 419 } 420 421 422 int numElements = elements.size(); 423 if (numElements != 8) 424 { 425 Message message = 426 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(numElements); 427 throw new LDAPException(PROTOCOL_ERROR, message); 428 } 429 430 431 ASN1OctetString baseDN; 432 try 433 { 434 baseDN = elements.get(0).decodeAsOctetString(); 435 } 436 catch (Exception e) 437 { 438 if (debugEnabled()) 439 { 440 TRACER.debugCaught(DebugLogLevel.ERROR, e); 441 } 442 443 Message message = 444 ERR_LDAP_SEARCH_REQUEST_DECODE_BASE.get(String.valueOf(e)); 445 throw new LDAPException(PROTOCOL_ERROR, message, e); 446 } 447 448 449 SearchScope scope; 450 try 451 { 452 switch (elements.get(1).decodeAsEnumerated().intValue()) 453 { 454 case SCOPE_BASE_OBJECT: 455 scope = SearchScope.BASE_OBJECT; 456 break; 457 case SCOPE_SINGLE_LEVEL: 458 scope = SearchScope.SINGLE_LEVEL; 459 break; 460 case SCOPE_WHOLE_SUBTREE: 461 scope = SearchScope.WHOLE_SUBTREE; 462 break; 463 case SCOPE_SUBORDINATE_SUBTREE: 464 scope = SearchScope.SUBORDINATE_SUBTREE; 465 break; 466 default: 467 int scopeValue = elements.get(1).decodeAsEnumerated().intValue(); 468 Message message = 469 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE.get(scopeValue); 470 throw new LDAPException(PROTOCOL_ERROR, message); 471 } 472 } 473 catch (LDAPException le) 474 { 475 throw le; 476 } 477 catch (Exception e) 478 { 479 if (debugEnabled()) 480 { 481 TRACER.debugCaught(DebugLogLevel.ERROR, e); 482 } 483 484 Message message = 485 ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE.get(String.valueOf(e)); 486 throw new LDAPException(PROTOCOL_ERROR, message, e); 487 } 488 489 490 DereferencePolicy dereferencePolicy; 491 try 492 { 493 switch (elements.get(2).decodeAsEnumerated().intValue()) 494 { 495 case DEREF_NEVER: 496 dereferencePolicy = DereferencePolicy.NEVER_DEREF_ALIASES; 497 break; 498 case DEREF_IN_SEARCHING: 499 dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING; 500 break; 501 case DEREF_FINDING_BASE: 502 dereferencePolicy = DereferencePolicy.DEREF_FINDING_BASE_OBJECT; 503 break; 504 case DEREF_ALWAYS: 505 dereferencePolicy = DereferencePolicy.DEREF_ALWAYS; 506 break; 507 default: 508 int derefValue = elements.get(2).decodeAsEnumerated().intValue(); 509 Message message = 510 ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF.get(derefValue); 511 throw new LDAPException(PROTOCOL_ERROR, message); 512 } 513 } 514 catch (LDAPException le) 515 { 516 throw le; 517 } 518 catch (Exception e) 519 { 520 if (debugEnabled()) 521 { 522 TRACER.debugCaught(DebugLogLevel.ERROR, e); 523 } 524 525 Message message = 526 ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF.get(String.valueOf(e)); 527 throw new LDAPException(PROTOCOL_ERROR, message, e); 528 } 529 530 531 int sizeLimit; 532 try 533 { 534 sizeLimit = elements.get(3).decodeAsInteger().intValue(); 535 } 536 catch (Exception e) 537 { 538 if (debugEnabled()) 539 { 540 TRACER.debugCaught(DebugLogLevel.ERROR, e); 541 } 542 543 Message message = 544 ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT.get(String.valueOf(e)); 545 throw new LDAPException(PROTOCOL_ERROR, message, e); 546 } 547 548 549 int timeLimit; 550 try 551 { 552 timeLimit = elements.get(4).decodeAsInteger().intValue(); 553 } 554 catch (Exception e) 555 { 556 if (debugEnabled()) 557 { 558 TRACER.debugCaught(DebugLogLevel.ERROR, e); 559 } 560 561 Message message = 562 ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT.get(String.valueOf(e)); 563 throw new LDAPException(PROTOCOL_ERROR, message, e); 564 } 565 566 567 boolean typesOnly; 568 try 569 { 570 typesOnly = elements.get(5).decodeAsBoolean().booleanValue(); 571 } 572 catch (Exception e) 573 { 574 if (debugEnabled()) 575 { 576 TRACER.debugCaught(DebugLogLevel.ERROR, e); 577 } 578 579 Message message = 580 ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY.get(String.valueOf(e)); 581 throw new LDAPException(PROTOCOL_ERROR, message, e); 582 } 583 584 585 LDAPFilter filter; 586 try 587 { 588 filter = LDAPFilter.decode(elements.get(6)); 589 } 590 catch (Exception e) 591 { 592 if (debugEnabled()) 593 { 594 TRACER.debugCaught(DebugLogLevel.ERROR, e); 595 } 596 597 Message message = 598 ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER.get(String.valueOf(e)); 599 throw new LDAPException(PROTOCOL_ERROR, message, e); 600 } 601 602 603 LinkedHashSet<String> attributes; 604 try 605 { 606 ArrayList<ASN1Element> attrElements = 607 elements.get(7).decodeAsSequence().elements(); 608 attributes = new LinkedHashSet<String>(attrElements.size()); 609 for (ASN1Element e: attrElements) 610 { 611 attributes.add(e.decodeAsOctetString().stringValue()); 612 } 613 } 614 catch (Exception e) 615 { 616 if (debugEnabled()) 617 { 618 TRACER.debugCaught(DebugLogLevel.ERROR, e); 619 } 620 621 Message message = 622 ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES.get(String.valueOf(e)); 623 throw new LDAPException(PROTOCOL_ERROR, message, e); 624 } 625 626 627 return new SearchRequestProtocolOp(baseDN, scope, dereferencePolicy, 628 sizeLimit, timeLimit, typesOnly, filter, 629 attributes); 630 } 631 632 633 634 /** 635 * Appends a string representation of this LDAP protocol op to the provided 636 * buffer. 637 * 638 * @param buffer The buffer to which the string should be appended. 639 */ 640 public void toString(StringBuilder buffer) 641 { 642 buffer.append("SearchRequest(baseDN="); 643 baseDN.toString(buffer); 644 buffer.append(", scope="); 645 buffer.append(String.valueOf(scope)); 646 buffer.append(", derefPolicy="); 647 buffer.append(String.valueOf(dereferencePolicy)); 648 buffer.append(", sizeLimit="); 649 buffer.append(sizeLimit); 650 buffer.append(", timeLimit="); 651 buffer.append(timeLimit); 652 buffer.append(", typesOnly="); 653 buffer.append(typesOnly); 654 buffer.append(", filter="); 655 filter.toString(buffer); 656 buffer.append(", attributes={"); 657 658 if ((attributes != null) && (! attributes.isEmpty())) 659 { 660 Iterator<String> iterator = attributes.iterator(); 661 buffer.append(iterator.next()); 662 663 while (iterator.hasNext()) 664 { 665 buffer.append(", "); 666 buffer.append(iterator.next()); 667 } 668 } 669 670 buffer.append("})"); 671 } 672 673 674 675 /** 676 * Appends a multi-line string representation of this LDAP protocol op to the 677 * provided buffer. 678 * 679 * @param buffer The buffer to which the information should be appended. 680 * @param indent The number of spaces from the margin that the lines should 681 * be indented. 682 */ 683 public void toString(StringBuilder buffer, int indent) 684 { 685 StringBuilder indentBuf = new StringBuilder(indent); 686 for (int i=0 ; i < indent; i++) 687 { 688 indentBuf.append(' '); 689 } 690 691 buffer.append(indentBuf); 692 buffer.append("Search Request"); 693 buffer.append(EOL); 694 695 buffer.append(indentBuf); 696 buffer.append(" Base DN: "); 697 baseDN.toString(buffer); 698 buffer.append(EOL); 699 700 buffer.append(indentBuf); 701 buffer.append(" Scope: "); 702 buffer.append(String.valueOf(scope)); 703 buffer.append(EOL); 704 705 buffer.append(indentBuf); 706 buffer.append(" Dereference Policy: "); 707 buffer.append(String.valueOf(dereferencePolicy)); 708 buffer.append(EOL); 709 710 buffer.append(indentBuf); 711 buffer.append(" Size Limit: "); 712 buffer.append(sizeLimit); 713 buffer.append(EOL); 714 715 buffer.append(indentBuf); 716 buffer.append(" Time Limit: "); 717 buffer.append(timeLimit); 718 buffer.append(EOL); 719 720 buffer.append(indentBuf); 721 buffer.append(" Types Only: "); 722 buffer.append(typesOnly); 723 buffer.append(EOL); 724 725 buffer.append(indentBuf); 726 buffer.append(" Filter: "); 727 filter.toString(buffer); 728 buffer.append(EOL); 729 730 buffer.append(indentBuf); 731 buffer.append(" Attributes:"); 732 buffer.append(EOL); 733 734 if (attributes != null) 735 { 736 for (String attribute : attributes) 737 { 738 buffer.append(indentBuf); 739 buffer.append(" "); 740 buffer.append(attribute); 741 buffer.append(EOL); 742 } 743 } 744 } 745 } 746