001    /*
002     * Copyright 2009-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2015 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    
125        final ASN1OctetString responseValue = response.getValue();
126        if (responseValue == null)
127        {
128          value = null;
129        }
130        else
131        {
132          value = new ASN1OctetString(TYPE_VALUE, responseValue.getValue());
133        }
134      }
135    
136    
137    
138      /**
139       * Creates a new intermediate response protocol op read from the provided
140       * ASN.1 stream reader.
141       *
142       * @param  reader  The ASN.1 stream reader from which to read the intermediate
143       *                 response protocol op.
144       *
145       * @throws  LDAPException  If a problem occurs while reading or parsing the
146       *                         intermediate response.
147       */
148      IntermediateResponseProtocolOp(final ASN1StreamReader reader)
149           throws LDAPException
150      {
151        try
152        {
153          final ASN1StreamReaderSequence opSequence = reader.beginSequence();
154    
155          String o = null;
156          ASN1OctetString v = null;
157          while (opSequence.hasMoreElements())
158          {
159            final byte type = (byte) reader.peek();
160            if (type == TYPE_OID)
161            {
162              o = reader.readString();
163            }
164            else if (type == TYPE_VALUE)
165            {
166              v = new ASN1OctetString(type, reader.readBytes());
167            }
168            else
169            {
170              throw new LDAPException(ResultCode.DECODING_ERROR,
171                   ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(toHex(type)));
172            }
173          }
174    
175          oid = o;
176          value = v;
177        }
178        catch (LDAPException le)
179        {
180          debugException(le);
181          throw le;
182        }
183        catch (Exception e)
184        {
185          debugException(e);
186    
187          throw new LDAPException(ResultCode.DECODING_ERROR,
188               ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)),
189               e);
190        }
191      }
192    
193    
194    
195      /**
196       * Retrieves the OID for this intermediate response, if any.
197       *
198       * @return  The OID for this intermediate response, or {@code null} if there
199       *          is no response OID.
200       */
201      public String getOID()
202      {
203        return oid;
204      }
205    
206    
207    
208      /**
209       * Retrieves the value for this intermediate response, if any.
210       *
211       * @return  The value for this intermediate response, or {@code null} if there
212       *          is no response value.
213       */
214      public ASN1OctetString getValue()
215      {
216        return value;
217      }
218    
219    
220    
221      /**
222       * {@inheritDoc}
223       */
224      public byte getProtocolOpType()
225      {
226        return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE;
227      }
228    
229    
230    
231      /**
232       * {@inheritDoc}
233       */
234      public ASN1Element encodeProtocolOp()
235      {
236        final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
237    
238        if (oid != null)
239        {
240          elements.add(new ASN1OctetString(TYPE_OID, oid));
241        }
242    
243        if (value != null)
244        {
245          elements.add(value);
246        }
247    
248        return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE,
249             elements);
250      }
251    
252    
253    
254      /**
255       * Decodes the provided ASN.1 element as a intermediate response protocol op.
256       *
257       * @param  element  The ASN.1 element to be decoded.
258       *
259       * @return  The decoded intermediate response protocol op.
260       *
261       * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
262       *                         a intermediate response protocol op.
263       */
264      public static IntermediateResponseProtocolOp decodeProtocolOp(
265                                                        final ASN1Element element)
266             throws LDAPException
267      {
268        try
269        {
270          String oid = null;
271          ASN1OctetString value = null;
272          for (final ASN1Element e :
273               ASN1Sequence.decodeAsSequence(element).elements())
274          {
275            switch (e.getType())
276            {
277              case TYPE_OID:
278                oid = ASN1OctetString.decodeAsOctetString(e).stringValue();
279                break;
280              case TYPE_VALUE:
281                value = ASN1OctetString.decodeAsOctetString(e);
282                break;
283              default:
284                throw new LDAPException(ResultCode.DECODING_ERROR,
285                     ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(
286                          toHex(e.getType())));
287            }
288          }
289    
290          return new IntermediateResponseProtocolOp(oid, value);
291        }
292        catch (final LDAPException le)
293        {
294          debugException(le);
295          throw le;
296        }
297        catch (final Exception e)
298        {
299          debugException(e);
300          throw new LDAPException(ResultCode.DECODING_ERROR,
301               ERR_COMPARE_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)),
302               e);
303        }
304      }
305    
306    
307    
308      /**
309       * {@inheritDoc}
310       */
311      public void writeTo(final ASN1Buffer buffer)
312      {
313        final ASN1BufferSequence opSequence = buffer.beginSequence(
314             LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE);
315    
316        if (oid != null)
317        {
318          buffer.addOctetString(TYPE_OID, oid);
319        }
320    
321        if (value != null)
322        {
323          buffer.addElement(value);
324        }
325    
326        opSequence.end();
327      }
328    
329    
330    
331      /**
332       * Creates a intermediate response from this protocol op.
333       *
334       * @param  controls  The set of controls to include in the intermediate
335       *                   response.  It may be empty or {@code null} if no controls
336       *                   should be included.
337       *
338       * @return  The intermediate response that was created.
339       */
340      public IntermediateResponse toIntermediateResponse(final Control... controls)
341      {
342        return new IntermediateResponse(-1, oid, value, controls);
343      }
344    
345    
346    
347      /**
348       * Retrieves a string representation of this protocol op.
349       *
350       * @return  A string representation of this protocol op.
351       */
352      @Override()
353      public String toString()
354      {
355        final StringBuilder buffer = new StringBuilder();
356        toString(buffer);
357        return buffer.toString();
358      }
359    
360    
361    
362      /**
363       * {@inheritDoc}
364       */
365      public void toString(final StringBuilder buffer)
366      {
367        buffer.append("IntermediateResponseProtocolOp(");
368    
369        if (oid != null)
370        {
371          buffer.append("oid='");
372          buffer.append(oid);
373          buffer.append('\'');
374        }
375    
376        buffer.append(')');
377      }
378    }