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.io.Serializable;
026    import java.util.ArrayList;
027    
028    import com.unboundid.asn1.ASN1StreamReader;
029    import com.unboundid.asn1.ASN1StreamReaderSequence;
030    import com.unboundid.ldap.protocol.LDAPResponse;
031    import com.unboundid.util.NotMutable;
032    import com.unboundid.util.ThreadSafety;
033    import com.unboundid.util.ThreadSafetyLevel;
034    
035    import static com.unboundid.ldap.sdk.LDAPMessages.*;
036    import static com.unboundid.util.Debug.*;
037    import static com.unboundid.util.StaticUtils.*;
038    import static com.unboundid.util.Validator.*;
039    
040    
041    
042    /**
043     * This class provides a data structure for representing an LDAP search result
044     * reference.  A search result reference consists of a set of referral URLs and
045     * may also include zero or more controls.  It describes an alternate location
046     * in which additional results for the search may be found.  If there are
047     * multiple referral URLs, then they should all be considered equivalent ways
048     * to access the information (e.g., referrals referencing different servers that
049     * may be contacted).
050     */
051    @NotMutable()
052    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
053    public final class SearchResultReference
054           implements Serializable, LDAPResponse
055    {
056      /**
057       * The serial version UID for this serializable class.
058       */
059      private static final long serialVersionUID = 5675961266319346053L;
060    
061    
062    
063      // The set of controls returned with this search result reference.
064      private final Control[] controls;
065    
066      // The message ID for the LDAP message containing this response.
067      private final int messageID;
068    
069      // The set of referral URLs for this search result reference.
070      private final String[] referralURLs;
071    
072    
073    
074      /**
075       * Creates a new search result reference with the provided information.
076       *
077       * @param  referralURLs  The set of referral URLs for this search result
078       *                       reference.  It must not be {@code null}.
079       * @param  controls      The set of controls returned with this search result
080       *                       reference.  It must not be {@code null}.
081       */
082      public SearchResultReference(final String[] referralURLs,
083                                   final Control[] controls)
084      {
085        this(-1, referralURLs, controls);
086      }
087    
088    
089    
090      /**
091       * Creates a new search result reference with the provided information.
092       *
093       * @param  messageID     The message ID for the LDAP message containing this
094       *                       response.
095       * @param  referralURLs  The set of referral URLs for this search result
096       *                       reference.  It must not be {@code null}.
097       * @param  controls      The set of controls returned with this search result
098       *                       reference.  It must not be {@code null}.
099       */
100      public SearchResultReference(final int messageID, final String[] referralURLs,
101                                   final Control[] controls)
102      {
103        ensureNotNull(referralURLs);
104    
105        this.messageID    = messageID;
106        this.referralURLs = referralURLs;
107    
108        if (controls == null)
109        {
110          this.controls = NO_CONTROLS;
111        }
112        else
113        {
114          this.controls = controls;
115        }
116      }
117    
118    
119    
120      /**
121       * Creates a new search result reference object with the protocol op and
122       * controls read from the given ASN.1 stream reader.
123       *
124       * @param  messageID        The message ID for the LDAP message containing
125       *                          this response.
126       * @param  messageSequence  The ASN.1 stream reader sequence used in the
127       *                          course of reading the LDAP message elements.
128       * @param  reader           The ASN.1 stream reader from which to read the
129       *                          protocol op and controls.
130       *
131       * @return  The decoded search result reference object.
132       *
133       * @throws  LDAPException  If a problem occurs while reading or decoding data
134       *                         from the ASN.1 stream reader.
135       */
136      static SearchResultReference readSearchReferenceFrom(final int messageID,
137                  final ASN1StreamReaderSequence messageSequence,
138                  final ASN1StreamReader reader)
139             throws LDAPException
140      {
141        try
142        {
143          final ArrayList<String> refList = new ArrayList<String>(5);
144          final ASN1StreamReaderSequence refSequence = reader.beginSequence();
145          while (refSequence.hasMoreElements())
146          {
147            refList.add(reader.readString());
148          }
149    
150          final String[] referralURLs = new String[refList.size()];
151          refList.toArray(referralURLs);
152    
153          Control[] controls = NO_CONTROLS;
154          if (messageSequence.hasMoreElements())
155          {
156            final ArrayList<Control> controlList = new ArrayList<Control>(5);
157            final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
158            while (controlSequence.hasMoreElements())
159            {
160              controlList.add(Control.readFrom(reader));
161            }
162    
163            controls = new Control[controlList.size()];
164            controlList.toArray(controls);
165          }
166    
167          return new SearchResultReference(messageID, referralURLs, controls);
168        }
169        catch (LDAPException le)
170        {
171          debugException(le);
172          throw le;
173        }
174        catch (Exception e)
175        {
176          debugException(e);
177          throw new LDAPException(ResultCode.DECODING_ERROR,
178               ERR_SEARCH_REFERENCE_CANNOT_DECODE.get(getExceptionMessage(e)), e);
179        }
180      }
181    
182    
183    
184      /**
185       * {@inheritDoc}
186       */
187      public int getMessageID()
188      {
189        return messageID;
190      }
191    
192    
193    
194      /**
195       * Retrieves the set of referral URLs for this search result reference.
196       *
197       * @return  The set of referral URLs for this search result reference.
198       */
199      public String[] getReferralURLs()
200      {
201        return referralURLs;
202      }
203    
204    
205    
206      /**
207       * Retrieves the set of controls returned with this search result reference.
208       * Individual response controls of a specific type may be retrieved and
209       * decoded using the {@code get} method in the response control class.
210       *
211       * @return  The set of controls returned with this search result reference.
212       */
213      public Control[] getControls()
214      {
215        return controls;
216      }
217    
218    
219    
220      /**
221       * Retrieves the control with the specified OID.  If there is more than one
222       * control with the given OID, then the first will be returned.
223       *
224       * @param  oid  The OID of the control to retrieve.
225       *
226       * @return  The control with the requested OID, or {@code null} if there is no
227       *          such control for this search result reference.
228       */
229      public Control getControl(final String oid)
230      {
231        for (final Control c : controls)
232        {
233          if (c.getOID().equals(oid))
234          {
235            return c;
236          }
237        }
238    
239        return null;
240      }
241    
242    
243    
244      /**
245       * Retrieves a string representation of this search result reference.
246       *
247       * @return  A string representation of this search result reference.
248       */
249      @Override()
250      public String toString()
251      {
252        final StringBuilder buffer = new StringBuilder();
253        toString(buffer);
254        return buffer.toString();
255      }
256    
257    
258    
259      /**
260       * Appends a string representation of this search result reference to the
261       * provided buffer.
262       *
263       * @param  buffer  The buffer to which to append the string representation of
264       *                 this search result reference.
265       */
266      public void toString(final StringBuilder buffer)
267      {
268        buffer.append("SearchResultReference(referralURLs={");
269        for (int i=0; i < referralURLs.length; i++)
270        {
271          if (i > 0)
272          {
273            buffer.append(", ");
274          }
275          buffer.append(referralURLs[i]);
276        }
277        buffer.append('}');
278    
279        if (messageID >= 0)
280        {
281          buffer.append(", messageID=");
282          buffer.append(messageID);
283        }
284    
285        buffer.append(", controls={");
286    
287        for (int i=0; i < controls.length; i++)
288        {
289          if (i > 0)
290          {
291            buffer.append(", ");
292          }
293    
294          controls[i].toString(buffer);
295        }
296    
297        buffer.append("})");
298      }
299    }