001    /*
002     * Copyright 2009-2013 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2013 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    
027    import com.unboundid.asn1.ASN1Buffer;
028    import com.unboundid.asn1.ASN1BufferSequence;
029    import com.unboundid.asn1.ASN1Element;
030    import com.unboundid.asn1.ASN1OctetString;
031    import com.unboundid.asn1.ASN1Sequence;
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.IntermediateResponse;
036    import com.unboundid.ldap.sdk.LDAPException;
037    import com.unboundid.ldap.sdk.ResultCode;
038    import com.unboundid.util.NotMutable;
039    import com.unboundid.util.InternalUseOnly;
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    
047    
048    
049    /**
050     * This class provides an implementation of an LDAP intermediate response
051     * protocol op.
052     */
053    @InternalUseOnly()
054    @NotMutable()
055    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
056    public final class IntermediateResponseProtocolOp
057           implements ProtocolOp
058    {
059      /**
060       * The BER type for the OID element.
061       */
062      public static final byte TYPE_OID = (byte) 0x80;
063    
064    
065    
066      /**
067       * The BER type for the value element.
068       */
069      public static final byte TYPE_VALUE = (byte) 0x81;
070    
071    
072    
073      /**
074       * The serial version UID for this serializable class.
075       */
076      private static final long serialVersionUID = 118549806265654465L;
077    
078    
079    
080      // The value for this intermediate response.
081      private final ASN1OctetString value;
082    
083      // The OID for this intermediate response.
084      private final String oid;
085    
086    
087    
088      /**
089       * Creates a new intermediate response protocol op with the provided
090       * information.
091       *
092       * @param  oid    The OID for this intermediate response, or {@code null} if
093       *                there should not be an OID.
094       * @param  value  The value for this intermediate response, or {@code null} if
095       *                there should not be a value.
096       */
097      public IntermediateResponseProtocolOp(final String oid,
098                                            final ASN1OctetString value)
099      {
100        this.oid = oid;
101    
102        if (value == null)
103        {
104          this.value = null;
105        }
106        else
107        {
108          this.value = new ASN1OctetString(TYPE_VALUE, value.getValue());
109        }
110      }
111    
112    
113    
114      /**
115       * Creates a new intermediate response protocol op from the provided
116       * intermediate response object.
117       *
118       * @param  response  The intermediate response object to use to create this
119       *                   protocol op.
120       */
121      public IntermediateResponseProtocolOp(final IntermediateResponse response)
122      {
123        oid   = response.getOID();
124        value = response.getValue();
125      }
126    
127    
128    
129      /**
130       * Creates a new intermediate response protocol op read from the provided
131       * ASN.1 stream reader.
132       *
133       * @param  reader  The ASN.1 stream reader from which to read the intermediate
134       *                 response protocol op.
135       *
136       * @throws  LDAPException  If a problem occurs while reading or parsing the
137       *                         intermediate response.
138       */
139      IntermediateResponseProtocolOp(final ASN1StreamReader reader)
140           throws LDAPException
141      {
142        try
143        {
144          final ASN1StreamReaderSequence opSequence = reader.beginSequence();
145    
146          String o = null;
147          ASN1OctetString v = null;
148          while (opSequence.hasMoreElements())
149          {
150            final byte type = (byte) reader.peek();
151            if (type == TYPE_OID)
152            {
153              o = reader.readString();
154            }
155            else if (type == TYPE_VALUE)
156            {
157              v = new ASN1OctetString(type, reader.readBytes());
158            }
159            else
160            {
161              throw new LDAPException(ResultCode.DECODING_ERROR,
162                   ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(toHex(type)));
163            }
164          }
165    
166          oid = o;
167          value = v;
168        }
169        catch (LDAPException le)
170        {
171          debugException(le);
172          throw le;
173        }
174        catch (Exception e)
175        {
176          debugException(e);
177    
178          throw new LDAPException(ResultCode.DECODING_ERROR,
179               ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)),
180               e);
181        }
182      }
183    
184    
185    
186      /**
187       * Retrieves the OID for this intermediate response, if any.
188       *
189       * @return  The OID for this intermediate response, or {@code null} if there
190       *          is no response OID.
191       */
192      public String getOID()
193      {
194        return oid;
195      }
196    
197    
198    
199      /**
200       * Retrieves the value for this intermediate response, if any.
201       *
202       * @return  The value for this intermediate response, or {@code null} if there
203       *          is no response value.
204       */
205      public ASN1OctetString getValue()
206      {
207        return value;
208      }
209    
210    
211    
212      /**
213       * {@inheritDoc}
214       */
215      public byte getProtocolOpType()
216      {
217        return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE;
218      }
219    
220    
221    
222      /**
223       * {@inheritDoc}
224       */
225      public ASN1Element encodeProtocolOp()
226      {
227        final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
228    
229        if (oid != null)
230        {
231          elements.add(new ASN1OctetString(TYPE_OID, oid));
232        }
233    
234        if (value != null)
235        {
236          elements.add(value);
237        }
238    
239        return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE,
240             elements);
241      }
242    
243    
244    
245      /**
246       * Decodes the provided ASN.1 element as a intermediate response protocol op.
247       *
248       * @param  element  The ASN.1 element to be decoded.
249       *
250       * @return  The decoded intermediate response protocol op.
251       *
252       * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
253       *                         a intermediate response protocol op.
254       */
255      public static IntermediateResponseProtocolOp decodeProtocolOp(
256                                                        final ASN1Element element)
257             throws LDAPException
258      {
259        try
260        {
261          String oid = null;
262          ASN1OctetString value = null;
263          for (final ASN1Element e :
264               ASN1Sequence.decodeAsSequence(element).elements())
265          {
266            switch (e.getType())
267            {
268              case TYPE_OID:
269                oid = ASN1OctetString.decodeAsOctetString(e).stringValue();
270                break;
271              case TYPE_VALUE:
272                value = ASN1OctetString.decodeAsOctetString(e);
273                break;
274              default:
275                throw new LDAPException(ResultCode.DECODING_ERROR,
276                     ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(
277                          toHex(e.getType())));
278            }
279          }
280    
281          return new IntermediateResponseProtocolOp(oid, value);
282        }
283        catch (final LDAPException le)
284        {
285          debugException(le);
286          throw le;
287        }
288        catch (final Exception e)
289        {
290          debugException(e);
291          throw new LDAPException(ResultCode.DECODING_ERROR,
292               ERR_COMPARE_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)),
293               e);
294        }
295      }
296    
297    
298    
299      /**
300       * {@inheritDoc}
301       */
302      public void writeTo(final ASN1Buffer buffer)
303      {
304        final ASN1BufferSequence opSequence = buffer.beginSequence(
305             LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE);
306    
307        if (oid != null)
308        {
309          buffer.addOctetString(TYPE_OID, oid);
310        }
311    
312        if (value != null)
313        {
314          buffer.addElement(value);
315        }
316    
317        opSequence.end();
318      }
319    
320    
321    
322      /**
323       * Creates a intermediate response from this protocol op.
324       *
325       * @param  controls  The set of controls to include in the intermediate
326       *                   response.  It may be empty or {@code null} if no controls
327       *                   should be included.
328       *
329       * @return  The intermediate response that was created.
330       */
331      public IntermediateResponse toIntermediateResponse(final Control... controls)
332      {
333        return new IntermediateResponse(-1, oid, value, controls);
334      }
335    
336    
337    
338      /**
339       * Retrieves a string representation of this protocol op.
340       *
341       * @return  A string representation of this protocol op.
342       */
343      @Override()
344      public String toString()
345      {
346        final StringBuilder buffer = new StringBuilder();
347        toString(buffer);
348        return buffer.toString();
349      }
350    
351    
352    
353      /**
354       * {@inheritDoc}
355       */
356      public void toString(final StringBuilder buffer)
357      {
358        buffer.append("IntermediateResponseProtocolOp(");
359    
360        if (oid != null)
361        {
362          buffer.append("oid='");
363          buffer.append(oid);
364          buffer.append('\'');
365        }
366    
367        buffer.append(')');
368      }
369    }