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