001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 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 provided message ID and with
180   * the protocol op and controls read from the given ASN.1 stream reader.
181   *
182   * @param  messageID        The LDAP message ID for the LDAP message that is
183   *                          associated with this LDAP result.
184   * @param  messageSequence  The ASN.1 stream reader sequence used in the
185   *                          course of reading the LDAP message elements.
186   * @param  reader           The ASN.1 stream reader from which to read the
187   *                          protocol op and controls.
188   *
189   * @return  The decoded search result object.
190   *
191   * @throws  LDAPException  If a problem occurs while reading or decoding data
192   *                         from the ASN.1 stream reader.
193   */
194  static SearchResult readSearchResultFrom(final int messageID,
195                           final ASN1StreamReaderSequence messageSequence,
196                           final ASN1StreamReader reader)
197         throws LDAPException
198  {
199    final LDAPResult r =
200         LDAPResult.readLDAPResultFrom(messageID, messageSequence, reader);
201
202    return new SearchResult(messageID, r.getResultCode(),
203         r.getDiagnosticMessage(), r.getMatchedDN(), r.getReferralURLs(),
204         -1, -1, r.getResponseControls());
205  }
206
207
208
209  /**
210   * Retrieves the number of matching entries returned for the search operation.
211   *
212   * @return  The number of matching entries returned for the search operation.
213   */
214  public int getEntryCount()
215  {
216    return numEntries;
217  }
218
219
220
221  /**
222   * Retrieves the number of search references returned for the search
223   * operation.  This may be zero even if search references were received if the
224   * connection used when processing the search was configured to automatically
225   * follow referrals.
226   *
227   * @return  The number of search references returned for the search operation.
228   */
229  public int getReferenceCount()
230  {
231    return numReferences;
232  }
233
234
235
236  /**
237   * Retrieves a list containing the matching entries returned from the search
238   * operation.  This will only be available if a {@code SearchResultListener}
239   * was not used during the search.
240   *
241   * @return  A list containing the matching entries returned from the search
242   *          operation, or {@code null} if a {@code SearchResultListener} was
243   *          used during the search.
244   */
245  public List<SearchResultEntry> getSearchEntries()
246  {
247    if (searchEntries == null)
248    {
249      return null;
250    }
251
252    return Collections.unmodifiableList(searchEntries);
253  }
254
255
256
257  /**
258   * Retrieves the search result entry with the specified DN from the set of
259   * entries returned.  This will only be available if a
260   * {@code SearchResultListener} was not used during the search.
261   *
262   * @param  dn  The DN of the search result entry to retrieve.  It must not
263   *             be {@code null}.
264   *
265   * @return  The search result entry with the provided DN, or {@code null} if
266   *          the specified entry was not returned, or if a
267   *          {@code SearchResultListener} was used for the search.
268   *
269   * @throws  LDAPException  If a problem is encountered while attempting to
270   *                         parse the provided DN or a search entry DN.
271   */
272  public SearchResultEntry getSearchEntry(final String dn)
273         throws LDAPException
274  {
275    if (searchEntries == null)
276    {
277      return null;
278    }
279
280    final DN parsedDN = new DN(dn);
281    for (final SearchResultEntry e : searchEntries)
282    {
283      if (parsedDN.equals(e.getParsedDN()))
284      {
285        return e;
286      }
287    }
288
289    return null;
290  }
291
292
293
294  /**
295   * Retrieves a list containing the search references returned from the search
296   * operation.  This will only be available if a {@code SearchResultListener}
297   * was not used during the search, and may be empty even if search references
298   * were received if the connection used when processing the search was
299   * configured to automatically follow referrals.
300   *
301   * @return  A list containing the search references returned from the search
302   *          operation, or {@code null} if a {@code SearchResultListener} was
303   *          used during the search.
304   */
305  public List<SearchResultReference> getSearchReferences()
306  {
307    if (searchReferences == null)
308    {
309      return null;
310    }
311
312    return Collections.unmodifiableList(searchReferences);
313  }
314
315
316
317  /**
318   * Provides information about the entries and references returned for the
319   * search operation.  This must only be called when a search result is created
320   * and the search result must not be altered at any point after that.
321   *
322   * @param  numEntries        The number of entries returned for the search
323   *                           operation.
324   * @param  searchEntries     A list containing the entries returned from the
325   *                           search operation, or {@code null} if a
326   *                           {@code SearchResultListener} was used during the
327   *                           search.
328   * @param  numReferences     The number of references returned for the search
329   *                           operation.
330   * @param  searchReferences  A list containing the search references returned
331   *                           from the search operation, or {@code null} if a
332   *                           {@code SearchResultListener} was used during the
333   *                           search.
334   */
335  void setCounts(final int numEntries,
336                 final List<SearchResultEntry> searchEntries,
337                 final int numReferences,
338                 final List<SearchResultReference> searchReferences)
339  {
340    this.numEntries    = numEntries;
341    this.numReferences = numReferences;
342
343    if (searchEntries == null)
344    {
345      this.searchEntries = null;
346    }
347    else
348    {
349      this.searchEntries = Collections.unmodifiableList(searchEntries);
350    }
351
352    if (searchReferences == null)
353    {
354      this.searchReferences = null;
355    }
356    else
357    {
358      this.searchReferences = Collections.unmodifiableList(searchReferences);
359    }
360  }
361
362
363
364  /**
365   * Appends a string representation of this LDAP result to the provided buffer.
366   *
367   * @param  buffer  The buffer to which to append a string representation of
368   *                 this LDAP result.
369   */
370  @Override()
371  public void toString(final StringBuilder buffer)
372  {
373    buffer.append("SearchResult(resultCode=");
374    buffer.append(getResultCode());
375
376    final int messageID = getMessageID();
377    if (messageID >= 0)
378    {
379      buffer.append(", messageID=");
380      buffer.append(messageID);
381    }
382
383    final String diagnosticMessage = getDiagnosticMessage();
384    if (diagnosticMessage != null)
385    {
386      buffer.append(", diagnosticMessage='");
387      buffer.append(diagnosticMessage);
388      buffer.append('\'');
389    }
390
391    final String matchedDN = getMatchedDN();
392    if (matchedDN != null)
393    {
394      buffer.append(", matchedDN='");
395      buffer.append(matchedDN);
396      buffer.append('\'');
397    }
398
399    final String[] referralURLs = getReferralURLs();
400    if (referralURLs.length > 0)
401    {
402      buffer.append(", referralURLs={");
403      for (int i=0; i < referralURLs.length; i++)
404      {
405        if (i > 0)
406        {
407          buffer.append(", ");
408        }
409
410        buffer.append('\'');
411        buffer.append(referralURLs[i]);
412        buffer.append('\'');
413      }
414      buffer.append('}');
415    }
416
417    if (numEntries >= 0)
418    {
419      buffer.append(", entriesReturned=");
420      buffer.append(numEntries);
421    }
422
423    if (numReferences >= 0)
424    {
425      buffer.append(", referencesReturned=");
426      buffer.append(numReferences);
427    }
428
429    final Control[] responseControls = getResponseControls();
430    if (responseControls.length > 0)
431    {
432      buffer.append(", responseControls={");
433      for (int i=0; i < responseControls.length; i++)
434      {
435        if (i > 0)
436        {
437          buffer.append(", ");
438        }
439
440        buffer.append(responseControls[i]);
441      }
442      buffer.append('}');
443    }
444
445    buffer.append(')');
446  }
447}