001    /*
002     * Copyright 2009-2012 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2012 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.ASN1OctetString;
033    import com.unboundid.asn1.ASN1StreamReader;
034    import com.unboundid.asn1.ASN1StreamReaderSequence;
035    import com.unboundid.ldap.sdk.LDAPException;
036    import com.unboundid.ldap.sdk.ResultCode;
037    import com.unboundid.util.NotMutable;
038    import com.unboundid.util.InternalUseOnly;
039    import com.unboundid.util.ThreadSafety;
040    import com.unboundid.util.ThreadSafetyLevel;
041    
042    import static com.unboundid.ldap.protocol.ProtocolMessages.*;
043    import static com.unboundid.util.Debug.*;
044    import static com.unboundid.util.StaticUtils.*;
045    import static com.unboundid.util.Validator.*;
046    
047    
048    
049    /**
050     * This class provides an implementation of a extended response protocol op.
051     */
052    @InternalUseOnly()
053    @NotMutable()
054    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
055    public final class ExtendedResponseProtocolOp
056           implements ProtocolOp
057    {
058      /**
059       * The BER type for the response OID element.
060       */
061      public static final byte TYPE_RESPONSE_OID = (byte) 0x8A;
062    
063    
064    
065      /**
066       * The BER type for the response value element.
067       */
068      public static final byte TYPE_RESPONSE_VALUE = (byte) 0x8B;
069    
070    
071    
072      /**
073       * The serial version UID for this serializable class.
074       */
075      private static final long serialVersionUID = -7757619031268544913L;
076    
077    
078    
079      // The value for this extended response.
080      private final ASN1OctetString responseValue;
081    
082      // The result code for this extended response.
083      private final int resultCode;
084    
085      // The referral URLs for this extended response.
086      private final List<String> referralURLs;
087    
088      // The diagnostic message for this extended response.
089      private final String diagnosticMessage;
090    
091      // The matched DN for this extended response.
092      private final String matchedDN;
093    
094      // The OID for this extended response.
095      private final String responseOID;
096    
097    
098    
099      /**
100       * Creates a new instance of this extended response protocol op with the
101       * provided information.
102       *
103       * @param  resultCode         The result code for this response.
104       * @param  matchedDN          The matched DN for this response, if available.
105       * @param  diagnosticMessage  The diagnostic message for this response, if
106       *                            any.
107       * @param  referralURLs       The list of referral URLs for this response, if
108       *                            any.
109       * @param  responseOID        The response OID for this response, if any.
110       * @param  responseValue      The value for this response, if any.
111       */
112      public ExtendedResponseProtocolOp(final int resultCode,
113                                        final String matchedDN,
114                                        final String diagnosticMessage,
115                                        final List<String> referralURLs,
116                                        final String responseOID,
117                                        final ASN1OctetString responseValue)
118      {
119        this.resultCode        = resultCode;
120        this.matchedDN         = matchedDN;
121        this.diagnosticMessage = diagnosticMessage;
122        this.responseOID       = responseOID;
123    
124        if (referralURLs == null)
125        {
126          this.referralURLs = Collections.emptyList();
127        }
128        else
129        {
130          this.referralURLs = Collections.unmodifiableList(referralURLs);
131        }
132    
133        if (responseValue == null)
134        {
135          this.responseValue = null;
136        }
137        else
138        {
139          this.responseValue =
140               new ASN1OctetString(TYPE_RESPONSE_VALUE, responseValue.getValue());
141        }
142      }
143    
144    
145    
146      /**
147       * Creates a new extended response protocol op read from the provided ASN.1
148       * stream reader.
149       *
150       * @param  reader  The ASN.1 stream reader from which to read the extended
151       *                 response.
152       *
153       * @throws  LDAPException  If a problem occurs while reading or parsing the
154       *                         extended response.
155       */
156      ExtendedResponseProtocolOp(final ASN1StreamReader reader)
157           throws LDAPException
158      {
159        try
160        {
161          final ASN1StreamReaderSequence opSequence = reader.beginSequence();
162          resultCode = reader.readEnumerated();
163    
164          String s = reader.readString();
165          ensureNotNull(s);
166          if (s.length() == 0)
167          {
168            matchedDN = null;
169          }
170          else
171          {
172            matchedDN = s;
173          }
174    
175          s = reader.readString();
176          ensureNotNull(s);
177          if (s.length() == 0)
178          {
179            diagnosticMessage = null;
180          }
181          else
182          {
183            diagnosticMessage = s;
184          }
185    
186          ASN1OctetString value = null;
187          String oid = null;
188          final ArrayList<String> refs = new ArrayList<String>(1);
189          while (opSequence.hasMoreElements())
190          {
191            final byte type = (byte) reader.peek();
192            if (type == GenericResponseProtocolOp.TYPE_REFERRALS)
193            {
194              final ASN1StreamReaderSequence refSequence = reader.beginSequence();
195              while (refSequence.hasMoreElements())
196              {
197                refs.add(reader.readString());
198              }
199            }
200            else if (type == TYPE_RESPONSE_OID)
201            {
202              oid = reader.readString();
203            }
204            else if (type == TYPE_RESPONSE_VALUE)
205            {
206              value = new ASN1OctetString(type, reader.readBytes());
207            }
208            else
209            {
210              throw new LDAPException(ResultCode.DECODING_ERROR,
211                   ERR_EXTENDED_RESPONSE_INVALID_ELEMENT.get(toHex(type)));
212            }
213          }
214    
215          referralURLs  = Collections.unmodifiableList(refs);
216          responseOID   = oid;
217          responseValue = value;
218        }
219        catch (LDAPException le)
220        {
221          debugException(le);
222          throw le;
223        }
224        catch (Exception e)
225        {
226          debugException(e);
227          throw new LDAPException(ResultCode.DECODING_ERROR,
228               ERR_EXTENDED_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)), e);
229        }
230      }
231    
232    
233    
234      /**
235       * Retrieves the result code for this extended response.
236       *
237       * @return  The result code for this extended response.
238       */
239      public int getResultCode()
240      {
241        return resultCode;
242      }
243    
244    
245    
246      /**
247       * Retrieves the matched DN for this extended response, if any.
248       *
249       * @return  The matched DN for this extended response, or {@code null} if
250       *          there is no matched DN.
251       */
252      public String getMatchedDN()
253      {
254        return matchedDN;
255      }
256    
257    
258    
259      /**
260       * Retrieves the diagnostic message for this extended response, if any.
261       *
262       * @return  The diagnostic message for this extended response, or {@code null}
263       *          if there is no diagnostic message.
264       */
265      public String getDiagnosticMessage()
266      {
267        return diagnosticMessage;
268      }
269    
270    
271    
272      /**
273       * Retrieves the list of referral URLs for this extended response.
274       *
275       * @return  The list of referral URLs for this extended response, or an empty
276       *          list if there are no referral URLs.
277       */
278      public List<String> getReferralURLs()
279      {
280        return referralURLs;
281      }
282    
283    
284    
285      /**
286       * Retrieves the OID for this extended response, if any.
287       *
288       * @return  The OID for this extended response, or {@code null} if there is no
289       *          response OID.
290       */
291      public String getResponseOID()
292      {
293        return responseOID;
294      }
295    
296    
297    
298      /**
299       * Retrieves the value for this extended response, if any.
300       *
301       * @return  The value for this extended response, or {@code null} if there is
302       *          no response value.
303       */
304      public ASN1OctetString getResponseValue()
305      {
306        return responseValue;
307      }
308    
309    
310    
311      /**
312       * {@inheritDoc}
313       */
314      public byte getProtocolOpType()
315      {
316        return LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_RESPONSE;
317      }
318    
319    
320    
321      /**
322       * {@inheritDoc}
323       */
324      public void writeTo(final ASN1Buffer buffer)
325      {
326        final ASN1BufferSequence opSequence =
327             buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_RESPONSE);
328        buffer.addEnumerated(resultCode);
329        buffer.addOctetString(matchedDN);
330        buffer.addOctetString(diagnosticMessage);
331    
332        if (! referralURLs.isEmpty())
333        {
334          final ASN1BufferSequence refSequence =
335               buffer.beginSequence(GenericResponseProtocolOp.TYPE_REFERRALS);
336          for (final String s : referralURLs)
337          {
338            buffer.addOctetString(s);
339          }
340          refSequence.end();
341        }
342    
343        if (responseOID != null)
344        {
345          buffer.addOctetString(TYPE_RESPONSE_OID, responseOID);
346        }
347    
348        if (responseValue != null)
349        {
350          buffer.addOctetString(TYPE_RESPONSE_VALUE, responseValue.getValue());
351        }
352    
353        opSequence.end();
354      }
355    
356    
357    
358      /**
359       * Retrieves a string representation of this protocol op.
360       *
361       * @return  A string representation of this protocol op.
362       */
363      @Override()
364      public String toString()
365      {
366        final StringBuilder buffer = new StringBuilder();
367        toString(buffer);
368        return buffer.toString();
369      }
370    
371    
372    
373      /**
374       * {@inheritDoc}
375       */
376      public void toString(final StringBuilder buffer)
377      {
378        buffer.append("ExtendedResponseProtocolOp(resultCode=");
379        buffer.append(resultCode);
380    
381        if (matchedDN != null)
382        {
383          buffer.append(", matchedDN='");
384          buffer.append(matchedDN);
385          buffer.append('\'');
386        }
387    
388        if (diagnosticMessage != null)
389        {
390          buffer.append(", diagnosticMessage='");
391          buffer.append(diagnosticMessage);
392          buffer.append('\'');
393        }
394    
395        if (! referralURLs.isEmpty())
396        {
397          buffer.append(", referralURLs={");
398    
399          final Iterator<String> iterator = referralURLs.iterator();
400          while (iterator.hasNext())
401          {
402            buffer.append('\'');
403            buffer.append(iterator.next());
404            buffer.append('\'');
405            if (iterator.hasNext())
406            {
407              buffer.append(',');
408            }
409          }
410    
411          buffer.append('}');
412        }
413    
414        if (responseOID != null)
415        {
416          buffer.append(", responseOID='");
417          buffer.append(responseOID);
418          buffer.append('\'');
419        }
420    
421        buffer.append(')');
422      }
423    }