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 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 }