001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-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.protocol;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.Iterator;
028 import java.util.List;
029
030 import com.unboundid.asn1.ASN1Buffer;
031 import com.unboundid.asn1.ASN1BufferSequence;
032 import com.unboundid.asn1.ASN1StreamReader;
033 import com.unboundid.asn1.ASN1StreamReaderSequence;
034 import com.unboundid.ldap.sdk.Control;
035 import com.unboundid.ldap.sdk.LDAPException;
036 import com.unboundid.ldap.sdk.LDAPResult;
037 import com.unboundid.ldap.sdk.ResultCode;
038 import com.unboundid.util.InternalUseOnly;
039 import com.unboundid.util.NotExtensible;
040 import com.unboundid.util.ThreadSafety;
041 import com.unboundid.util.ThreadSafetyLevel;
042
043 import static com.unboundid.ldap.protocol.ProtocolMessages.*;
044 import static com.unboundid.util.Debug.*;
045 import static com.unboundid.util.StaticUtils.*;
046 import static com.unboundid.util.Validator.*;
047
048
049
050 /**
051 * This class provides an implementation of a generic response protocol op.
052 * It must be subclassed by classes providing implementations for each
053 * operation type.
054 */
055 @InternalUseOnly()
056 @NotExtensible()
057 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
058 public abstract class GenericResponseProtocolOp
059 implements ProtocolOp
060 {
061 /**
062 * The BER type for the referral URLs elements.
063 */
064 public static final byte TYPE_REFERRALS = (byte) 0xA3;
065
066
067
068 /**
069 * The serial version UID for this serializable class.
070 */
071 private static final long serialVersionUID = 3837308973105414874L;
072
073
074
075 // The BER type for this response.
076 private final byte type;
077
078 // The result code for this response.
079 private final int resultCode;
080
081 // The referral URLs for this response.
082 private final List<String> referralURLs;
083
084 // The diagnostic message for this response.
085 private final String diagnosticMessage;
086
087 // The matched DN for this response.Static
088 private final String matchedDN;
089
090
091
092 /**
093 * Creates a new instance of this response with the provided information.
094 *
095 * @param type The BER type for this response.
096 * @param resultCode The result code for this response.
097 * @param matchedDN The matched DN for this result, if available.
098 * @param diagnosticMessage The diagnostic message for this response, if
099 * available.
100 * @param referralURLs The list of referral URLs for this response, if
101 * available.
102 */
103 protected GenericResponseProtocolOp(final byte type, final int resultCode,
104 final String matchedDN,
105 final String diagnosticMessage,
106 final List<String> referralURLs)
107 {
108 this.type = type;
109 this.resultCode = resultCode;
110 this.matchedDN = matchedDN;
111 this.diagnosticMessage = diagnosticMessage;
112
113 if (referralURLs == null)
114 {
115 this.referralURLs = Collections.emptyList();
116 }
117 else
118 {
119 this.referralURLs = Collections.unmodifiableList(referralURLs);
120 }
121 }
122
123
124
125 /**
126 * Creates a new response read from the provided ASN.1 stream reader.
127 *
128 * @param reader The ASN.1 stream reader from which to read the response.
129 *
130 * @throws LDAPException If a problem occurs while reading or parsing the
131 * response.
132 */
133 protected GenericResponseProtocolOp(final ASN1StreamReader reader)
134 throws LDAPException
135 {
136 try
137 {
138 type = (byte) reader.peek();
139 final ASN1StreamReaderSequence opSequence = reader.beginSequence();
140 resultCode = reader.readEnumerated();
141
142 String s = reader.readString();
143 ensureNotNull(s);
144 if (s.length() == 0)
145 {
146 matchedDN = null;
147 }
148 else
149 {
150 matchedDN = s;
151 }
152
153 s = reader.readString();
154 ensureNotNull(s);
155 if (s.length() == 0)
156 {
157 diagnosticMessage = null;
158 }
159 else
160 {
161 diagnosticMessage = s;
162 }
163
164 if (opSequence.hasMoreElements())
165 {
166 final ArrayList<String> refs = new ArrayList<String>(1);
167 final ASN1StreamReaderSequence refSequence = reader.beginSequence();
168 while (refSequence.hasMoreElements())
169 {
170 refs.add(reader.readString());
171 }
172 referralURLs = Collections.unmodifiableList(refs);
173 }
174 else
175 {
176 referralURLs = Collections.emptyList();
177 }
178 }
179 catch (Exception e)
180 {
181 debugException(e);
182 throw new LDAPException(ResultCode.DECODING_ERROR,
183 ERR_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)), e);
184 }
185 }
186
187
188
189 /**
190 * Retrieves the result code for this response.
191 *
192 * @return The result code for this response.
193 */
194 public final int getResultCode()
195 {
196 return resultCode;
197 }
198
199
200
201 /**
202 * Retrieves the matched DN for this response, if any.
203 *
204 * @return The matched DN for this response, or {@code null} if there is
205 * no matched DN.
206 */
207 public final String getMatchedDN()
208 {
209 return matchedDN;
210 }
211
212
213
214 /**
215 * Retrieves the diagnostic message for this response, if any.
216 *
217 * @return The diagnostic message for this response, or {@code null} if there
218 * is no diagnostic message.
219 */
220 public final String getDiagnosticMessage()
221 {
222 return diagnosticMessage;
223 }
224
225
226
227 /**
228 * Retrieves the list of referral URLs for this response.
229 *
230 * @return The list of referral URLs for this response, or an empty list
231 * if there are no referral URLs.
232 */
233 public final List<String> getReferralURLs()
234 {
235 return referralURLs;
236 }
237
238
239
240 /**
241 * {@inheritDoc}
242 */
243 public byte getProtocolOpType()
244 {
245 return type;
246 }
247
248
249
250 /**
251 * {@inheritDoc}
252 */
253 public final void writeTo(final ASN1Buffer buffer)
254 {
255 final ASN1BufferSequence opSequence = buffer.beginSequence(type);
256 buffer.addEnumerated(resultCode);
257 buffer.addOctetString(matchedDN);
258 buffer.addOctetString(diagnosticMessage);
259
260 if (! referralURLs.isEmpty())
261 {
262 final ASN1BufferSequence refSequence =
263 buffer.beginSequence(TYPE_REFERRALS);
264 for (final String s : referralURLs)
265 {
266 buffer.addOctetString(s);
267 }
268 refSequence.end();
269 }
270 opSequence.end();
271 }
272
273
274
275 /**
276 * Creates a new LDAP result object from this response protocol op.
277 *
278 * @param controls The set of controls to include in the LDAP result. It
279 * may be empty or {@code null} if no controls should be
280 * included.
281 *
282 * @return The LDAP result that was created.
283 */
284 public LDAPResult toLDAPResult(final Control... controls)
285 {
286 final String[] refs;
287 if (referralURLs.isEmpty())
288 {
289 refs = NO_STRINGS;
290 }
291 else
292 {
293 refs = new String[referralURLs.size()];
294 referralURLs.toArray(refs);
295 }
296
297 return new LDAPResult(-1, ResultCode.valueOf(resultCode), diagnosticMessage,
298 matchedDN, refs, controls);
299 }
300
301
302
303 /**
304 * Retrieves a string representation of this protocol op.
305 *
306 * @return A string representation of this protocol op.
307 */
308 @Override()
309 public final String toString()
310 {
311 final StringBuilder buffer = new StringBuilder();
312 toString(buffer);
313 return buffer.toString();
314 }
315
316
317
318 /**
319 * {@inheritDoc}
320 */
321 public final void toString(final StringBuilder buffer)
322 {
323 buffer.append("ResponseProtocolOp(type=");
324 toHex(type, buffer);
325 buffer.append(", resultCode=");
326 buffer.append(resultCode);
327
328 if (matchedDN != null)
329 {
330 buffer.append(", matchedDN='");
331 buffer.append(matchedDN);
332 buffer.append('\'');
333 }
334
335 if (diagnosticMessage != null)
336 {
337 buffer.append(", diagnosticMessage='");
338 buffer.append(diagnosticMessage);
339 buffer.append('\'');
340 }
341
342 if (! referralURLs.isEmpty())
343 {
344 buffer.append(", referralURLs={");
345
346 final Iterator<String> iterator = referralURLs.iterator();
347 while (iterator.hasNext())
348 {
349 buffer.append('\'');
350 buffer.append(iterator.next());
351 buffer.append('\'');
352 if (iterator.hasNext())
353 {
354 buffer.append(',');
355 }
356 }
357
358 buffer.append('}');
359 }
360 buffer.append(')');
361 }
362 }