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    
031    
032    
033    /**
034     * This class provides a data structure for holding information about the result
035     * of processing a search request.  This includes the elements of the
036     * {@code LDAPResult} object, but also contains additional information specific
037     * to the search operation.  This includes:
038     * <UL>
039     *   <LI>The number of {@code SearchResultEntry} objects returned from the
040     *       server.  This will be available regardless of whether the entries are
041     *       included in this search result object or were returned through a
042     *       {@code SearchResultListener}.</LI>
043     *   <LI>The number of {@code SearchResultReference} objects returned from the
044     *       server.  This will be available regardless of whether the entries are
045     *       included in this search result object or were returned through a
046     *       {@code SearchResultListener}.</LI>
047     *   <LI>A list of the {@code SearchResultEntry} objects returned from the
048     *       server.  This will be {@code null} if a {@code SearchResultListener}
049     *       was used to return the entries.</LI>
050     *   <LI>A list of the {@code SearchResultReference} objects returned from the
051     *       server.  This will be {@code null} if a {@code SearchResultListener}
052     *       was used to return the entries.</LI>
053     * </UL>
054     */
055    public final class SearchResult
056           extends LDAPResult
057    {
058      /**
059       * The serial version UID for this serializable class.
060       */
061      private static final long serialVersionUID = 1938208530894131198L;
062    
063    
064    
065      // The number of matching entries returned for this search.
066      private int numEntries;
067    
068      // The number of search result references returned for this search.
069      private int numReferences;
070    
071      // A list that may be used to hold the search result entries returned for
072      // this search.
073      private List<SearchResultEntry> searchEntries;
074    
075      // A list that may be used to hold the search result references returned for
076      // this search.
077      private List<SearchResultReference> searchReferences;
078    
079    
080    
081      /**
082       * Creates a new search result object with the provided information.  This
083       * version of the constructor should be used if the search result entries and
084       * references were returned to the client via the {@code SearchResultListener}
085       * interface.
086       *
087       * @param  messageID          The message ID for the LDAP message that is
088       *                            associated with this LDAP result.
089       * @param  resultCode         The result code from the search result done
090       *                            response.
091       * @param  diagnosticMessage  The diagnostic message from the search result
092       *                            done response, if available.
093       * @param  matchedDN          The matched DN from the search result done
094       *                            response, if available.
095       * @param  referralURLs       The set of referral URLs from the search result
096       *                            done response, if available.
097       * @param  numEntries         The number of search result entries returned
098       *                            for this search.
099       * @param  numReferences      The number of search result references returned
100       *                            for this search.
101       * @param  responseControls   The set of controls from the search result done
102       *                            response, if available.
103       */
104      public SearchResult(final int messageID, final ResultCode resultCode,
105                          final String diagnosticMessage, final String matchedDN,
106                          final String[] referralURLs, final int numEntries,
107                          final int numReferences, final Control[] responseControls)
108      {
109        super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
110              responseControls);
111    
112        this.numEntries    = numEntries;
113        this.numReferences = numReferences;
114    
115        searchEntries    = null;
116        searchReferences = null;
117      }
118    
119    
120    
121      /**
122       * Creates a new search result object with the provided information.  This
123       * version of the constructor should be used if the search result entries and
124       * references were collected in lists rather than returned to the requester
125       * through the {@code SearchResultListener} interface.
126       *
127       * @param  messageID          The message ID for the LDAP message that is
128       *                            associated with this LDAP result.
129       * @param  resultCode         The result code from the search result done
130       *                            response.
131       * @param  diagnosticMessage  The diagnostic message from the search result
132       *                            done response, if available.
133       * @param  matchedDN          The matched DN from the search result done
134       *                            response, if available.
135       * @param  referralURLs       The set of referral URLs from the search result
136       *                            done response, if available.
137       * @param  searchEntries      A list containing the set of search result
138       *                            entries returned by the server.  It may only be
139       *                            {@code null} if the search result entries were
140       *                            returned through the
141       *                            {@code SearchResultListener} interface.
142       * @param  searchReferences   A list containing the set of search result
143       *                            references returned by the server.  It may only
144       *                            be {@code null} if the search result entries
145       *                            were returned through the
146       *                            {@code SearchResultListener} interface.
147       * @param  numEntries         The number of search result entries returned
148       *                            for this search.
149       * @param  numReferences      The number of search result references returned
150       *                            for this search.
151       * @param  responseControls   The set of controls from the search result done
152       *                            response, if available.
153       */
154      public SearchResult(final int messageID, final ResultCode resultCode,
155                          final String diagnosticMessage, final String matchedDN,
156                          final String[] referralURLs,
157                          final List<SearchResultEntry> searchEntries,
158                          final List<SearchResultReference> searchReferences,
159                          final int numEntries, final int numReferences,
160                          final Control[] responseControls)
161      {
162        super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
163              responseControls);
164    
165        this.numEntries       = numEntries;
166        this.numReferences    = numReferences;
167        this.searchEntries    = searchEntries;
168        this.searchReferences = searchReferences;
169      }
170    
171    
172    
173      /**
174       * Creates a new search result object with the provided message ID and with
175       * the protocol op and controls read from the given ASN.1 stream reader.
176       *
177       * @param  messageID        The LDAP message ID for the LDAP message that is
178       *                          associated with this LDAP result.
179       * @param  messageSequence  The ASN.1 stream reader sequence used in the
180       *                          course of reading the LDAP message elements.
181       * @param  reader           The ASN.1 stream reader from which to read the
182       *                          protocol op and controls.
183       *
184       * @return  The decoded search result object.
185       *
186       * @throws  LDAPException  If a problem occurs while reading or decoding data
187       *                         from the ASN.1 stream reader.
188       */
189      static SearchResult readSearchResultFrom(final int messageID,
190                               final ASN1StreamReaderSequence messageSequence,
191                               final ASN1StreamReader reader)
192             throws LDAPException
193      {
194        final LDAPResult r =
195             LDAPResult.readLDAPResultFrom(messageID, messageSequence, reader);
196    
197        return new SearchResult(messageID, r.getResultCode(),
198             r.getDiagnosticMessage(), r.getMatchedDN(), r.getReferralURLs(),
199             -1, -1, r.getResponseControls());
200      }
201    
202    
203    
204      /**
205       * Retrieves the number of matching entries returned for the search operation.
206       *
207       * @return  The number of matching entries returned for the search operation.
208       */
209      public int getEntryCount()
210      {
211        return numEntries;
212      }
213    
214    
215    
216      /**
217       * Retrieves the number of search references returned for the search
218       * operation.  This may be zero even if search references were received if the
219       * connection used when processing the search was configured to automatically
220       * follow referrals.
221       *
222       * @return  The number of search references returned for the search operation.
223       */
224      public int getReferenceCount()
225      {
226        return numReferences;
227      }
228    
229    
230    
231      /**
232       * Retrieves a list containing the matching entries returned from the search
233       * operation.  This will only be available if a {@code SearchResultListener}
234       * was not used during the search.
235       *
236       * @return  A list containing the matching entries returned from the search
237       *          operation, or {@code null} if a {@code SearchResultListener} was
238       *          used during the search.
239       */
240      public List<SearchResultEntry> getSearchEntries()
241      {
242        if (searchEntries == null)
243        {
244          return null;
245        }
246    
247        return Collections.unmodifiableList(searchEntries);
248      }
249    
250    
251    
252      /**
253       * Retrieves the search result entry with the specified DN from the set of
254       * entries returned.  This will only be available if a
255       * {@code SearchResultListener} was not used during the search.
256       *
257       * @param  dn  The DN of the search result entry to retrieve.  It must not
258       *             be {@code null}.
259       *
260       * @return  The search result entry with the provided DN, or {@code null} if
261       *          the specified entry was not returned, or if a
262       *          {@code SearchResultListener} was used for the search.
263       *
264       * @throws  LDAPException  If a problem is encountered while attempting to
265       *                         parse the provided DN or a search entry DN.
266       */
267      public SearchResultEntry getSearchEntry(final String dn)
268             throws LDAPException
269      {
270        if (searchEntries == null)
271        {
272          return null;
273        }
274    
275        final DN parsedDN = new DN(dn);
276        for (final SearchResultEntry e : searchEntries)
277        {
278          if (parsedDN.equals(e.getParsedDN()))
279          {
280            return e;
281          }
282        }
283    
284        return null;
285      }
286    
287    
288    
289      /**
290       * Retrieves a list containing the search references returned from the search
291       * operation.  This will only be available if a {@code SearchResultListener}
292       * was not used during the search, and may be empty even if search references
293       * were received if the connection used when processing the search was
294       * configured to automatically follow referrals.
295       *
296       * @return  A list containing the search references returned from the search
297       *          operation, or {@code null} if a {@code SearchResultListener} was
298       *          used during the search.
299       */
300      public List<SearchResultReference> getSearchReferences()
301      {
302        if (searchReferences == null)
303        {
304          return null;
305        }
306    
307        return Collections.unmodifiableList(searchReferences);
308      }
309    
310    
311    
312      /**
313       * Provides information about the entries and references returned for the
314       * search operation.  This must only be called when a search result is created
315       * and the search result must not be altered at any point after that.
316       *
317       * @param  numEntries        The number of entries returned for the search
318       *                           operation.
319       * @param  searchEntries     A list containing the entries returned from the
320       *                           search operation, or {@code null} if a
321       *                           {@code SearchResultListener} was used during the
322       *                           search.
323       * @param  numReferences     The number of references returned for the search
324       *                           operation.
325       * @param  searchReferences  A list containing the search references returned
326       *                           from the search operation, or {@code null} if a
327       *                           {@code SearchResultListener} was used during the
328       *                           search.
329       */
330      void setCounts(final int numEntries,
331                     final List<SearchResultEntry> searchEntries,
332                     final int numReferences,
333                     final List<SearchResultReference> searchReferences)
334      {
335        this.numEntries    = numEntries;
336        this.numReferences = numReferences;
337    
338        if (searchEntries == null)
339        {
340          this.searchEntries = null;
341        }
342        else
343        {
344          this.searchEntries = Collections.unmodifiableList(searchEntries);
345        }
346    
347        if (searchReferences == null)
348        {
349          this.searchReferences = null;
350        }
351        else
352        {
353          this.searchReferences = Collections.unmodifiableList(searchReferences);
354        }
355      }
356    
357    
358    
359      /**
360       * Appends a string representation of this LDAP result to the provided buffer.
361       *
362       * @param  buffer  The buffer to which to append a string representation of
363       *                 this LDAP result.
364       */
365      @Override()
366      public void toString(final StringBuilder buffer)
367      {
368        buffer.append("SearchResult(resultCode=");
369        buffer.append(getResultCode());
370    
371        final int messageID = getMessageID();
372        if (messageID >= 0)
373        {
374          buffer.append(", messageID=");
375          buffer.append(messageID);
376        }
377    
378        final String diagnosticMessage = getDiagnosticMessage();
379        if (diagnosticMessage != null)
380        {
381          buffer.append(", diagnosticMessage='");
382          buffer.append(diagnosticMessage);
383          buffer.append('\'');
384        }
385    
386        final String matchedDN = getMatchedDN();
387        if (matchedDN != null)
388        {
389          buffer.append(", matchedDN='");
390          buffer.append(matchedDN);
391          buffer.append('\'');
392        }
393    
394        final String[] referralURLs = getReferralURLs();
395        if (referralURLs.length > 0)
396        {
397          buffer.append(", referralURLs={");
398          for (int i=0; i < referralURLs.length; i++)
399          {
400            if (i > 0)
401            {
402              buffer.append(", ");
403            }
404    
405            buffer.append('\'');
406            buffer.append(referralURLs[i]);
407            buffer.append('\'');
408          }
409          buffer.append('}');
410        }
411    
412        if (numEntries >= 0)
413        {
414          buffer.append(", entriesReturned=");
415          buffer.append(numEntries);
416        }
417    
418        if (numReferences >= 0)
419        {
420          buffer.append(", referencesReturned=");
421          buffer.append(numReferences);
422        }
423    
424        final Control[] responseControls = getResponseControls();
425        if (responseControls.length > 0)
426        {
427          buffer.append(", responseControls={");
428          for (int i=0; i < responseControls.length; i++)
429          {
430            if (i > 0)
431            {
432              buffer.append(", ");
433            }
434    
435            buffer.append(responseControls[i]);
436          }
437          buffer.append('}');
438        }
439    
440        buffer.append(')');
441      }
442    }