001/* 002 * Copyright 2007-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import java.util.Collections; 026import java.util.List; 027 028import com.unboundid.asn1.ASN1StreamReader; 029import com.unboundid.asn1.ASN1StreamReaderSequence; 030import com.unboundid.util.NotMutable; 031import com.unboundid.util.ThreadSafety; 032import com.unboundid.util.ThreadSafetyLevel; 033 034 035 036/** 037 * This class provides a data structure for holding information about the result 038 * of processing a search request. This includes the elements of the 039 * {@link LDAPResult} object, but also contains additional information specific 040 * to the search operation. This includes: 041 * <UL> 042 * <LI>The number of {@link SearchResultEntry} objects returned from the 043 * server. This will be available regardless of whether the entries are 044 * included in this search result object or were returned through a 045 * {@link SearchResultListener}.</LI> 046 * <LI>The number of {@link SearchResultReference} objects returned from the 047 * server. This will be available regardless of whether the entries are 048 * included in this search result object or were returned through a 049 * {@link SearchResultListener}.</LI> 050 * <LI>A list of the {@link SearchResultEntry} objects returned from the 051 * server. This will be {@code null} if a {@link SearchResultListener} 052 * was used to return the entries.</LI> 053 * <LI>A list of the {@link SearchResultReference} objects returned from the 054 * server. This will be {@code null} if a {@link SearchResultListener} 055 * was used to return the entries.</LI> 056 * </UL> 057 */ 058@NotMutable() 059@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 060public final class SearchResult 061 extends LDAPResult 062{ 063 /** 064 * The serial version UID for this serializable class. 065 */ 066 private static final long serialVersionUID = 1938208530894131198L; 067 068 069 070 // The number of matching entries returned for this search. 071 private int numEntries; 072 073 // The number of search result references returned for this search. 074 private int numReferences; 075 076 // A list that may be used to hold the search result entries returned for 077 // this search. 078 private List<SearchResultEntry> searchEntries; 079 080 // A list that may be used to hold the search result references returned for 081 // this search. 082 private List<SearchResultReference> searchReferences; 083 084 085 086 /** 087 * Creates a new search result object with the provided information. This 088 * version of the constructor should be used if the search result entries and 089 * references were returned to the client via the {@code SearchResultListener} 090 * interface. 091 * 092 * @param messageID The message ID for the LDAP message that is 093 * associated with this LDAP result. 094 * @param resultCode The result code from the search result done 095 * response. 096 * @param diagnosticMessage The diagnostic message from the search result 097 * done response, if available. 098 * @param matchedDN The matched DN from the search result done 099 * response, if available. 100 * @param referralURLs The set of referral URLs from the search result 101 * done response, if available. 102 * @param numEntries The number of search result entries returned 103 * for this search. 104 * @param numReferences The number of search result references returned 105 * for this search. 106 * @param responseControls The set of controls from the search result done 107 * response, if available. 108 */ 109 public SearchResult(final int messageID, final ResultCode resultCode, 110 final String diagnosticMessage, final String matchedDN, 111 final String[] referralURLs, final int numEntries, 112 final int numReferences, final Control[] responseControls) 113 { 114 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 115 responseControls); 116 117 this.numEntries = numEntries; 118 this.numReferences = numReferences; 119 120 searchEntries = null; 121 searchReferences = null; 122 } 123 124 125 126 /** 127 * Creates a new search result object with the provided information. This 128 * version of the constructor should be used if the search result entries and 129 * references were collected in lists rather than returned to the requester 130 * through the {@code SearchResultListener} interface. 131 * 132 * @param messageID The message ID for the LDAP message that is 133 * associated with this LDAP result. 134 * @param resultCode The result code from the search result done 135 * response. 136 * @param diagnosticMessage The diagnostic message from the search result 137 * done response, if available. 138 * @param matchedDN The matched DN from the search result done 139 * response, if available. 140 * @param referralURLs The set of referral URLs from the search result 141 * done response, if available. 142 * @param searchEntries A list containing the set of search result 143 * entries returned by the server. It may only be 144 * {@code null} if the search result entries were 145 * returned through the 146 * {@code SearchResultListener} interface. 147 * @param searchReferences A list containing the set of search result 148 * references returned by the server. It may only 149 * be {@code null} if the search result entries 150 * were returned through the 151 * {@code SearchResultListener} interface. 152 * @param numEntries The number of search result entries returned 153 * for this search. 154 * @param numReferences The number of search result references returned 155 * for this search. 156 * @param responseControls The set of controls from the search result done 157 * response, if available. 158 */ 159 public SearchResult(final int messageID, final ResultCode resultCode, 160 final String diagnosticMessage, final String matchedDN, 161 final String[] referralURLs, 162 final List<SearchResultEntry> searchEntries, 163 final List<SearchResultReference> searchReferences, 164 final int numEntries, final int numReferences, 165 final Control[] responseControls) 166 { 167 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 168 responseControls); 169 170 this.numEntries = numEntries; 171 this.numReferences = numReferences; 172 this.searchEntries = searchEntries; 173 this.searchReferences = searchReferences; 174 } 175 176 177 178 /** 179 * Creates a new search result object with the information from the provided 180 * LDAP result. 181 * 182 * @param ldapResult The LDAP result to use to create the contents of this 183 * search result. 184 */ 185 public SearchResult(final LDAPResult ldapResult) 186 { 187 super(ldapResult); 188 189 if (ldapResult instanceof SearchResult) 190 { 191 final SearchResult searchResult = (SearchResult) ldapResult; 192 numEntries = searchResult.numEntries; 193 numReferences = searchResult.numReferences; 194 searchEntries = searchResult.searchEntries; 195 searchReferences = searchResult.searchReferences; 196 } 197 else 198 { 199 numEntries = -1; 200 numReferences = -1; 201 searchEntries = null; 202 searchReferences = null; 203 } 204 } 205 206 207 208 /** 209 * Creates a new search result object with the information from the provided 210 * LDAP exception. 211 * 212 * @param ldapException The LDAP exception to use to create the contents of 213 * this search result. 214 */ 215 public SearchResult(final LDAPException ldapException) 216 { 217 this(ldapException.toLDAPResult()); 218 } 219 220 221 222 /** 223 * Creates a new search result object with the provided message ID and with 224 * the protocol op and controls read from the given ASN.1 stream reader. 225 * 226 * @param messageID The LDAP message ID for the LDAP message that is 227 * associated with this LDAP result. 228 * @param messageSequence The ASN.1 stream reader sequence used in the 229 * course of reading the LDAP message elements. 230 * @param reader The ASN.1 stream reader from which to read the 231 * protocol op and controls. 232 * 233 * @return The decoded search result object. 234 * 235 * @throws LDAPException If a problem occurs while reading or decoding data 236 * from the ASN.1 stream reader. 237 */ 238 static SearchResult readSearchResultFrom(final int messageID, 239 final ASN1StreamReaderSequence messageSequence, 240 final ASN1StreamReader reader) 241 throws LDAPException 242 { 243 final LDAPResult r = 244 LDAPResult.readLDAPResultFrom(messageID, messageSequence, reader); 245 246 return new SearchResult(messageID, r.getResultCode(), 247 r.getDiagnosticMessage(), r.getMatchedDN(), r.getReferralURLs(), 248 -1, -1, r.getResponseControls()); 249 } 250 251 252 253 /** 254 * Retrieves the number of matching entries returned for the search operation. 255 * 256 * @return The number of matching entries returned for the search operation. 257 */ 258 public int getEntryCount() 259 { 260 return numEntries; 261 } 262 263 264 265 /** 266 * Retrieves the number of search references returned for the search 267 * operation. This may be zero even if search references were received if the 268 * connection used when processing the search was configured to automatically 269 * follow referrals. 270 * 271 * @return The number of search references returned for the search operation. 272 */ 273 public int getReferenceCount() 274 { 275 return numReferences; 276 } 277 278 279 280 /** 281 * Retrieves a list containing the matching entries returned from the search 282 * operation. This will only be available if a {@code SearchResultListener} 283 * was not used during the search. 284 * 285 * @return A list containing the matching entries returned from the search 286 * operation, or {@code null} if a {@code SearchResultListener} was 287 * used during the search. 288 */ 289 public List<SearchResultEntry> getSearchEntries() 290 { 291 if (searchEntries == null) 292 { 293 return null; 294 } 295 296 return Collections.unmodifiableList(searchEntries); 297 } 298 299 300 301 /** 302 * Retrieves the search result entry with the specified DN from the set of 303 * entries returned. This will only be available if a 304 * {@code SearchResultListener} was not used during the search. 305 * 306 * @param dn The DN of the search result entry to retrieve. It must not 307 * be {@code null}. 308 * 309 * @return The search result entry with the provided DN, or {@code null} if 310 * the specified entry was not returned, or if a 311 * {@code SearchResultListener} was used for the search. 312 * 313 * @throws LDAPException If a problem is encountered while attempting to 314 * parse the provided DN or a search entry DN. 315 */ 316 public SearchResultEntry getSearchEntry(final String dn) 317 throws LDAPException 318 { 319 if (searchEntries == null) 320 { 321 return null; 322 } 323 324 final DN parsedDN = new DN(dn); 325 for (final SearchResultEntry e : searchEntries) 326 { 327 if (parsedDN.equals(e.getParsedDN())) 328 { 329 return e; 330 } 331 } 332 333 return null; 334 } 335 336 337 338 /** 339 * Retrieves a list containing the search references returned from the search 340 * operation. This will only be available if a {@code SearchResultListener} 341 * was not used during the search, and may be empty even if search references 342 * were received if the connection used when processing the search was 343 * configured to automatically follow referrals. 344 * 345 * @return A list containing the search references returned from the search 346 * operation, or {@code null} if a {@code SearchResultListener} was 347 * used during the search. 348 */ 349 public List<SearchResultReference> getSearchReferences() 350 { 351 if (searchReferences == null) 352 { 353 return null; 354 } 355 356 return Collections.unmodifiableList(searchReferences); 357 } 358 359 360 361 /** 362 * Provides information about the entries and references returned for the 363 * search operation. This must only be called when a search result is created 364 * and the search result must not be altered at any point after that. 365 * 366 * @param numEntries The number of entries returned for the search 367 * operation. 368 * @param searchEntries A list containing the entries returned from the 369 * search operation, or {@code null} if a 370 * {@code SearchResultListener} was used during the 371 * search. 372 * @param numReferences The number of references returned for the search 373 * operation. 374 * @param searchReferences A list containing the search references returned 375 * from the search operation, or {@code null} if a 376 * {@code SearchResultListener} was used during the 377 * search. 378 */ 379 void setCounts(final int numEntries, 380 final List<SearchResultEntry> searchEntries, 381 final int numReferences, 382 final List<SearchResultReference> searchReferences) 383 { 384 this.numEntries = numEntries; 385 this.numReferences = numReferences; 386 387 if (searchEntries == null) 388 { 389 this.searchEntries = null; 390 } 391 else 392 { 393 this.searchEntries = Collections.unmodifiableList(searchEntries); 394 } 395 396 if (searchReferences == null) 397 { 398 this.searchReferences = null; 399 } 400 else 401 { 402 this.searchReferences = Collections.unmodifiableList(searchReferences); 403 } 404 } 405 406 407 408 /** 409 * Appends a string representation of this LDAP result to the provided buffer. 410 * 411 * @param buffer The buffer to which to append a string representation of 412 * this LDAP result. 413 */ 414 @Override() 415 public void toString(final StringBuilder buffer) 416 { 417 buffer.append("SearchResult(resultCode="); 418 buffer.append(getResultCode()); 419 420 final int messageID = getMessageID(); 421 if (messageID >= 0) 422 { 423 buffer.append(", messageID="); 424 buffer.append(messageID); 425 } 426 427 final String diagnosticMessage = getDiagnosticMessage(); 428 if (diagnosticMessage != null) 429 { 430 buffer.append(", diagnosticMessage='"); 431 buffer.append(diagnosticMessage); 432 buffer.append('\''); 433 } 434 435 final String matchedDN = getMatchedDN(); 436 if (matchedDN != null) 437 { 438 buffer.append(", matchedDN='"); 439 buffer.append(matchedDN); 440 buffer.append('\''); 441 } 442 443 final String[] referralURLs = getReferralURLs(); 444 if (referralURLs.length > 0) 445 { 446 buffer.append(", referralURLs={"); 447 for (int i=0; i < referralURLs.length; i++) 448 { 449 if (i > 0) 450 { 451 buffer.append(", "); 452 } 453 454 buffer.append('\''); 455 buffer.append(referralURLs[i]); 456 buffer.append('\''); 457 } 458 buffer.append('}'); 459 } 460 461 if (numEntries >= 0) 462 { 463 buffer.append(", entriesReturned="); 464 buffer.append(numEntries); 465 } 466 467 if (numReferences >= 0) 468 { 469 buffer.append(", referencesReturned="); 470 buffer.append(numReferences); 471 } 472 473 final Control[] responseControls = getResponseControls(); 474 if (responseControls.length > 0) 475 { 476 buffer.append(", responseControls={"); 477 for (int i=0; i < responseControls.length; i++) 478 { 479 if (i > 0) 480 { 481 buffer.append(", "); 482 } 483 484 buffer.append(responseControls[i]); 485 } 486 buffer.append('}'); 487 } 488 489 buffer.append(')'); 490 } 491}