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