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 */
021 package com.unboundid.ldap.sdk;
022
023
024
025 import java.util.Collections;
026 import java.util.List;
027
028 import com.unboundid.asn1.ASN1StreamReader;
029 import com.unboundid.asn1.ASN1StreamReaderSequence;
030 import com.unboundid.util.NotMutable;
031 import com.unboundid.util.ThreadSafety;
032 import 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)
060 public 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 }