001    /*
002     * Copyright 2007-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 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 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    }