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