001    /*
002     * Copyright 2009-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-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.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.ASN1Element;
033    import com.unboundid.asn1.ASN1OctetString;
034    import com.unboundid.asn1.ASN1Sequence;
035    import com.unboundid.asn1.ASN1StreamReader;
036    import com.unboundid.asn1.ASN1StreamReaderSequence;
037    import com.unboundid.ldap.sdk.Attribute;
038    import com.unboundid.ldap.sdk.Control;
039    import com.unboundid.ldap.sdk.Entry;
040    import com.unboundid.ldap.sdk.LDAPException;
041    import com.unboundid.ldap.sdk.ResultCode;
042    import com.unboundid.ldap.sdk.SearchResultEntry;
043    import com.unboundid.util.NotMutable;
044    import com.unboundid.util.InternalUseOnly;
045    import com.unboundid.util.ThreadSafety;
046    import com.unboundid.util.ThreadSafetyLevel;
047    
048    import static com.unboundid.ldap.protocol.ProtocolMessages.*;
049    import static com.unboundid.util.Debug.*;
050    import static com.unboundid.util.StaticUtils.*;
051    import static com.unboundid.util.Validator.*;
052    
053    
054    
055    /**
056     * This class provides an implementation of an LDAP search result entry protocol
057     * op.
058     */
059    @InternalUseOnly()
060    @NotMutable()
061    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
062    public final class SearchResultEntryProtocolOp
063           implements ProtocolOp
064    {
065      /**
066       * The serial version UID for this serializable class.
067       */
068      private static final long serialVersionUID = 6501366526364541767L;
069    
070    
071    
072      // The list of attributes for this search result entry.
073      private final List<Attribute> attributes;
074    
075      // The entry DN for this search result entry.
076      private final String dn;
077    
078    
079    
080      /**
081       * Creates a new search result entry protocol op with the provided
082       * information.
083       *
084       * @param  dn          The entry DN for this search result entry.
085       * @param  attributes  The list of attributes to include in this search result
086       *                     entry.
087       */
088      public SearchResultEntryProtocolOp(final String dn,
089                                         final List<Attribute> attributes)
090      {
091        this.dn         = dn;
092        this.attributes = Collections.unmodifiableList(attributes);
093      }
094    
095    
096    
097      /**
098       * Creates a new search result entry protocol op from the provided entry.
099       *
100       * @param  entry  The entry to use to create this protocol op.
101       */
102      public SearchResultEntryProtocolOp(final Entry entry)
103      {
104        dn = entry.getDN();
105        attributes = Collections.unmodifiableList(new ArrayList<Attribute>(
106             entry.getAttributes()));
107      }
108    
109    
110    
111      /**
112       * Creates a new search result entry protocol op read from the provided ASN.1
113       * stream reader.
114       *
115       * @param  reader  The ASN.1 stream reader from which to read the search
116       *                 result entry protocol op.
117       *
118       * @throws  LDAPException  If a problem occurs while reading or parsing the
119       *                         search result entry.
120       */
121      SearchResultEntryProtocolOp(final ASN1StreamReader reader)
122           throws LDAPException
123      {
124        try
125        {
126          reader.beginSequence();
127          dn = reader.readString();
128          ensureNotNull(dn);
129    
130          final ArrayList<Attribute> attrs = new ArrayList<Attribute>(10);
131          final ASN1StreamReaderSequence attrSequence = reader.beginSequence();
132          while (attrSequence.hasMoreElements())
133          {
134            attrs.add(Attribute.readFrom(reader));
135          }
136    
137          attributes = Collections.unmodifiableList(attrs);
138        }
139        catch (LDAPException le)
140        {
141          debugException(le);
142          throw le;
143        }
144        catch (Exception e)
145        {
146          debugException(e);
147    
148          throw new LDAPException(ResultCode.DECODING_ERROR,
149               ERR_SEARCH_ENTRY_CANNOT_DECODE.get(getExceptionMessage(e)), e);
150        }
151      }
152    
153    
154    
155      /**
156       * Retrieves the DN for this search result entry.
157       *
158       * @return  The DN for this search result entry.
159       */
160      public String getDN()
161      {
162        return dn;
163      }
164    
165    
166    
167      /**
168       * Retrieves the list of attributes for this search result entry.
169       *
170       * @return  The list of attributes for this search result entry.
171       */
172      public List<Attribute> getAttributes()
173      {
174        return attributes;
175      }
176    
177    
178    
179      /**
180       * {@inheritDoc}
181       */
182      public byte getProtocolOpType()
183      {
184        return LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY;
185      }
186    
187    
188    
189      /**
190       * {@inheritDoc}
191       */
192      public ASN1Element encodeProtocolOp()
193      {
194        final ArrayList<ASN1Element> attrElements =
195             new ArrayList<ASN1Element>(attributes.size());
196        for (final Attribute a : attributes)
197        {
198          attrElements.add(a.encode());
199        }
200    
201        return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY,
202             new ASN1OctetString(dn),
203             new ASN1Sequence(attrElements));
204      }
205    
206    
207    
208      /**
209       * Decodes the provided ASN.1 element as a search result entry protocol op.
210       *
211       * @param  element  The ASN.1 element to be decoded.
212       *
213       * @return  The decoded search result entry protocol op.
214       *
215       * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
216       *                         a search result entry protocol op.
217       */
218      public static SearchResultEntryProtocolOp decodeProtocolOp(
219                                                     final ASN1Element element)
220             throws LDAPException
221      {
222        try
223        {
224          final ASN1Element[] elements =
225               ASN1Sequence.decodeAsSequence(element).elements();
226          final String dn =
227               ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
228    
229          final ASN1Element[] attrElements =
230               ASN1Sequence.decodeAsSequence(elements[1]).elements();
231          final ArrayList<Attribute> attributes =
232               new ArrayList<Attribute>(attrElements.length);
233          for (final ASN1Element e : attrElements)
234          {
235            attributes.add(Attribute.decode(ASN1Sequence.decodeAsSequence(e)));
236          }
237    
238          return new SearchResultEntryProtocolOp(dn, attributes);
239        }
240        catch (final Exception e)
241        {
242          debugException(e);
243          throw new LDAPException(ResultCode.DECODING_ERROR,
244               ERR_SEARCH_ENTRY_CANNOT_DECODE.get(getExceptionMessage(e)),
245               e);
246        }
247      }
248    
249    
250    
251      /**
252       * {@inheritDoc}
253       */
254      public void writeTo(final ASN1Buffer buffer)
255      {
256        final ASN1BufferSequence opSequence =
257             buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_ENTRY);
258        buffer.addOctetString(dn);
259    
260        final ASN1BufferSequence attrSequence = buffer.beginSequence();
261        for (final Attribute a : attributes)
262        {
263          a.writeTo(buffer);
264        }
265        attrSequence.end();
266        opSequence.end();
267      }
268    
269    
270    
271      /**
272       * Creates a search result entry from this protocol op.
273       *
274       * @param  controls  The set of controls to include in the search result
275       *                   entry.  It may be empty or {@code null} if no controls
276       *                   should be included.
277       *
278       * @return  The search result entry that was created.
279       */
280      public SearchResultEntry toSearchResultEntry(final Control... controls)
281      {
282        return new SearchResultEntry(dn, attributes, controls);
283      }
284    
285    
286    
287      /**
288       * Retrieves a string representation of this protocol op.
289       *
290       * @return  A string representation of this protocol op.
291       */
292      @Override()
293      public String toString()
294      {
295        final StringBuilder buffer = new StringBuilder();
296        toString(buffer);
297        return buffer.toString();
298      }
299    
300    
301    
302      /**
303       * {@inheritDoc}
304       */
305      public void toString(final StringBuilder buffer)
306      {
307        buffer.append("SearchResultEntryProtocolOp(dn='");
308        buffer.append(dn);
309        buffer.append("', attrs={");
310    
311        final Iterator<Attribute> iterator = attributes.iterator();
312        while (iterator.hasNext())
313        {
314          iterator.next().toString(buffer);
315          if (iterator.hasNext())
316          {
317            buffer.append(',');
318          }
319        }
320    
321        buffer.append("})");
322      }
323    }