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.util.ArrayList;
026 import java.util.Collection;
027 import java.util.Iterator;
028
029 import com.unboundid.asn1.ASN1StreamReader;
030 import com.unboundid.asn1.ASN1StreamReaderSequence;
031 import com.unboundid.ldap.protocol.LDAPResponse;
032 import com.unboundid.ldap.sdk.schema.Schema;
033
034 import static com.unboundid.ldap.sdk.LDAPMessages.*;
035 import static com.unboundid.util.Debug.*;
036 import static com.unboundid.util.StaticUtils.*;
037 import static com.unboundid.util.Validator.*;
038
039
040
041 /**
042 * This class provides a data structure for representing an LDAP search result
043 * entry. This is a {@code ReadOnlyEntry} object that may also include zero
044 * or more controls included with the entry returned from the server.
045 */
046 public final class SearchResultEntry
047 extends ReadOnlyEntry
048 implements LDAPResponse
049 {
050 /**
051 * The serial version UID for this serializable class.
052 */
053 private static final long serialVersionUID = -290721544252526163L;
054
055
056
057 // The set of controls returned with this search result entry.
058 private final Control[] controls;
059
060 // The message ID for the LDAP message containing this response.
061 private final int messageID;
062
063
064
065 /**
066 * Creates a new search result entry with the provided information.
067 *
068 * @param dn The DN for this search result entry. It must not be
069 * {@code null}.
070 * @param attributes The set of attributes to include in this search result
071 * entry. It must not be {@code null}.
072 * @param controls The set of controls for this search result entry. It
073 * must not be {@code null}.
074 */
075 public SearchResultEntry(final String dn, final Attribute[] attributes,
076 final Control... controls)
077 {
078 this(-1, dn, null, attributes, controls);
079 }
080
081
082
083 /**
084 * Creates a new search result entry with the provided information.
085 *
086 * @param messageID The message ID for the LDAP message containing this
087 * response.
088 * @param dn The DN for this search result entry. It must not be
089 * {@code null}.
090 * @param attributes The set of attributes to include in this search result
091 * entry. It must not be {@code null}.
092 * @param controls The set of controls for this search result entry. It
093 * must not be {@code null}.
094 */
095 public SearchResultEntry(final int messageID, final String dn,
096 final Attribute[] attributes,
097 final Control... controls)
098 {
099 this(messageID, dn, null, attributes, controls);
100 }
101
102
103
104 /**
105 * Creates a new search result entry with the provided information.
106 *
107 * @param messageID The message ID for the LDAP message containing this
108 * response.
109 * @param dn The DN for this search result entry. It must not be
110 * {@code null}.
111 * @param schema The schema to use for operations involving this entry.
112 * It may be {@code null} if no schema is available.
113 * @param attributes The set of attributes to include in this search result
114 * entry. It must not be {@code null}.
115 * @param controls The set of controls for this search result entry. It
116 * must not be {@code null}.
117 */
118 public SearchResultEntry(final int messageID, final String dn,
119 final Schema schema, final Attribute[] attributes,
120 final Control... controls)
121 {
122 super(dn, schema, attributes);
123
124 ensureNotNull(controls);
125
126 this.messageID = messageID;
127 this.controls = controls;
128 }
129
130
131
132 /**
133 * Creates a new search result entry with the provided information.
134 *
135 * @param dn The DN for this search result entry. It must not be
136 * {@code null}.
137 * @param attributes The set of attributes to include in this search result
138 * entry. It must not be {@code null}.
139 * @param controls The set of controls for this search result entry. It
140 * must not be {@code null}.
141 */
142 public SearchResultEntry(final String dn,
143 final Collection<Attribute> attributes,
144 final Control... controls)
145 {
146 this(-1, dn, null, attributes, controls);
147 }
148
149
150
151 /**
152 * Creates a new search result entry with the provided information.
153 *
154 * @param messageID The message ID for the LDAP message containing this
155 * response.
156 * @param dn The DN for this search result entry. It must not be
157 * {@code null}.
158 * @param attributes The set of attributes to include in this search result
159 * entry. It must not be {@code null}.
160 * @param controls The set of controls for this search result entry. It
161 * must not be {@code null}.
162 */
163 public SearchResultEntry(final int messageID, final String dn,
164 final Collection<Attribute> attributes,
165 final Control... controls)
166 {
167 this(messageID, dn, null, attributes, controls);
168 }
169
170
171
172 /**
173 * Creates a new search result entry with the provided information.
174 *
175 * @param messageID The message ID for the LDAP message containing this
176 * response.
177 * @param dn The DN for this search result entry. It must not be
178 * {@code null}.
179 * @param schema The schema to use for operations involving this entry.
180 * It may be {@code null} if no schema is available.
181 * @param attributes The set of attributes to include in this search result
182 * entry. It must not be {@code null}.
183 * @param controls The set of controls for this search result entry. It
184 * must not be {@code null}.
185 */
186 public SearchResultEntry(final int messageID, final String dn,
187 final Schema schema,
188 final Collection<Attribute> attributes,
189 final Control... controls)
190 {
191 super(dn, schema, attributes);
192
193 ensureNotNull(controls);
194
195 this.messageID = messageID;
196 this.controls = controls;
197 }
198
199
200
201 /**
202 * Creates a new search result entry from the provided entry.
203 *
204 * @param entry The entry to use to create this search result entry. It
205 * must not be {@code null}.
206 * @param controls The set of controls for this search result entry. It
207 * must not be {@code null}.
208 */
209 public SearchResultEntry(final Entry entry, final Control... controls)
210 {
211 this(-1, entry, controls);
212 }
213
214
215
216 /**
217 * Creates a new search result entry from the provided entry.
218 *
219 * @param messageID The message ID for the LDAP message containing this
220 * response.
221 * @param entry The entry to use to create this search result entry. It
222 * must not be {@code null}.
223 * @param controls The set of controls for this search result entry. It
224 * must not be {@code null}.
225 */
226 public SearchResultEntry(final int messageID, final Entry entry,
227 final Control... controls)
228 {
229 super(entry);
230
231 ensureNotNull(controls);
232
233 this.messageID = messageID;
234 this.controls = controls;
235 }
236
237
238
239 /**
240 * Creates a new search result entry object with the protocol op and controls
241 * read from the given ASN.1 stream reader.
242 *
243 * @param messageID The message ID for the LDAP message containing
244 * this response.
245 * @param messageSequence The ASN.1 stream reader sequence used in the
246 * course of reading the LDAP message elements.
247 * @param reader The ASN.1 stream reader from which to read the
248 * protocol op and controls.
249 * @param schema The schema to use to select the appropriate
250 * matching rule to use for each attribute. It may
251 * be {@code null} if the default matching rule
252 * should always be used.
253 *
254 * @return The decoded search result entry object.
255 *
256 * @throws LDAPException If a problem occurs while reading or decoding data
257 * from the ASN.1 stream reader.
258 */
259 static SearchResultEntry readSearchEntryFrom(final int messageID,
260 final ASN1StreamReaderSequence messageSequence,
261 final ASN1StreamReader reader, final Schema schema)
262 throws LDAPException
263 {
264 try
265 {
266 reader.beginSequence();
267 final String dn = reader.readString();
268
269 final ArrayList<Attribute> attrList = new ArrayList<Attribute>(10);
270 final ASN1StreamReaderSequence attrSequence = reader.beginSequence();
271 while (attrSequence.hasMoreElements())
272 {
273 attrList.add(Attribute.readFrom(reader, schema));
274 }
275
276 Control[] controls = NO_CONTROLS;
277 if (messageSequence.hasMoreElements())
278 {
279 final ArrayList<Control> controlList = new ArrayList<Control>(5);
280 final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
281 while (controlSequence.hasMoreElements())
282 {
283 controlList.add(Control.readFrom(reader));
284 }
285
286 controls = new Control[controlList.size()];
287 controlList.toArray(controls);
288 }
289
290 return new SearchResultEntry(messageID, dn, schema, attrList, controls);
291 }
292 catch (LDAPException le)
293 {
294 debugException(le);
295 throw le;
296 }
297 catch (Exception e)
298 {
299 debugException(e);
300 throw new LDAPException(ResultCode.DECODING_ERROR,
301 ERR_SEARCH_ENTRY_CANNOT_DECODE.get(getExceptionMessage(e)), e);
302 }
303 }
304
305
306
307 /**
308 * {@inheritDoc}
309 */
310 public int getMessageID()
311 {
312 return messageID;
313 }
314
315
316
317 /**
318 * Retrieves the set of controls returned with this search result entry.
319 * Individual response controls of a specific type may be retrieved and
320 * decoded using the {@code get} method in the response control class.
321 *
322 * @return The set of controls returned with this search result entry.
323 */
324 public Control[] getControls()
325 {
326 return controls;
327 }
328
329
330
331 /**
332 * Retrieves the control with the specified OID. If there is more than one
333 * control with the given OID, then the first will be returned.
334 *
335 * @param oid The OID of the control to retrieve.
336 *
337 * @return The control with the requested OID, or {@code null} if there is no
338 * such control for this search result entry.
339 */
340 public Control getControl(final String oid)
341 {
342 for (final Control c : controls)
343 {
344 if (c.getOID().equals(oid))
345 {
346 return c;
347 }
348 }
349
350 return null;
351 }
352
353
354
355 /**
356 * Generates a hash code for this entry.
357 *
358 * @return The generated hash code for this entry.
359 */
360 @Override()
361 public int hashCode()
362 {
363 int hashCode = super.hashCode();
364
365 for (final Control c : controls)
366 {
367 hashCode += c.hashCode();
368 }
369
370 return hashCode;
371 }
372
373
374
375 /**
376 * Indicates whether the provided object is equal to this entry. The provided
377 * object will only be considered equal to this entry if it is an entry with
378 * the same DN and set of attributes.
379 *
380 * @param o The object for which to make the determination.
381 *
382 * @return {@code true} if the provided object is considered equal to this
383 * entry, or {@code false} if not.
384 */
385 @Override()
386 public boolean equals(final Object o)
387 {
388 if (! super.equals(o))
389 {
390 return false;
391 }
392
393 if (! (o instanceof SearchResultEntry))
394 {
395 return false;
396 }
397
398 final SearchResultEntry e = (SearchResultEntry) o;
399
400 if (controls.length != e.controls.length)
401 {
402 return false;
403 }
404
405 for (int i=0; i < controls.length; i++)
406 {
407 if (! controls[i].equals(e.controls[i]))
408 {
409 return false;
410 }
411 }
412
413 return true;
414 }
415
416
417
418 /**
419 * Appends a string representation of this entry to the provided buffer.
420 *
421 * @param buffer The buffer to which to append the string representation of
422 * this entry.
423 */
424 @Override()
425 public void toString(final StringBuilder buffer)
426 {
427 buffer.append("SearchResultEntry(dn='");
428 buffer.append(getDN());
429 buffer.append('\'');
430
431 if (messageID >= 0)
432 {
433 buffer.append(", messageID=");
434 buffer.append(messageID);
435 }
436
437 buffer.append(", attributes={");
438
439 final Iterator<Attribute> iterator = getAttributes().iterator();
440
441 while (iterator.hasNext())
442 {
443 iterator.next().toString(buffer);
444 if (iterator.hasNext())
445 {
446 buffer.append(", ");
447 }
448 }
449
450 buffer.append("}, controls={");
451
452 for (int i=0; i < controls.length; i++)
453 {
454 if (i > 0)
455 {
456 buffer.append(", ");
457 }
458
459 controls[i].toString(buffer);
460 }
461
462 buffer.append("})");
463 }
464 }