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    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.ASN1StreamReader;
033    import com.unboundid.asn1.ASN1StreamReaderSequence;
034    import com.unboundid.ldap.sdk.Control;
035    import com.unboundid.ldap.sdk.LDAPException;
036    import com.unboundid.ldap.sdk.LDAPResult;
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    import static com.unboundid.util.Validator.*;
044    
045    
046    
047    /**
048     * This class provides an implementation of a generic response protocol op.
049     * It must be subclassed by classes providing implementations for each
050     * operation type.
051     */
052    @InternalUseOnly()
053    public abstract class GenericResponseProtocolOp
054           implements ProtocolOp
055    {
056      /**
057       * The BER type for the referral URLs elements.
058       */
059      public static final byte TYPE_REFERRALS = (byte) 0xA3;
060    
061    
062    
063      /**
064       * The serial version UID for this serializable class.
065       */
066      private static final long serialVersionUID = 3837308973105414874L;
067    
068    
069    
070      // The BER type for this response.
071      private final byte type;
072    
073      // The result code for this response.
074      private final int resultCode;
075    
076      // The referral URLs for this response.
077      private final List<String> referralURLs;
078    
079      // The diagnostic message for this response.
080      private final String diagnosticMessage;
081    
082      // The matched DN for this response.Static
083      private final String matchedDN;
084    
085    
086    
087      /**
088       * Creates a new instance of this response with the provided information.
089       *
090       * @param  type               The BER type for this response.
091       * @param  resultCode         The result code for this response.
092       * @param  matchedDN          The matched DN for this result, if available.
093       * @param  diagnosticMessage  The diagnostic message for this response, if
094       *                            available.
095       * @param  referralURLs       The list of referral URLs for this response, if
096       *                            available.
097       */
098      protected GenericResponseProtocolOp(final byte type, final int resultCode,
099                                        final String matchedDN,
100                                        final String diagnosticMessage,
101                                        final List<String> referralURLs)
102      {
103        this.type              = type;
104        this.resultCode        = resultCode;
105        this.matchedDN         = matchedDN;
106        this.diagnosticMessage = diagnosticMessage;
107    
108        if (referralURLs == null)
109        {
110          this.referralURLs = Collections.emptyList();
111        }
112        else
113        {
114          this.referralURLs = Collections.unmodifiableList(referralURLs);
115        }
116      }
117    
118    
119    
120      /**
121       * Creates a new response read from the provided ASN.1 stream reader.
122       *
123       * @param  reader  The ASN.1 stream reader from which to read the response.
124       *
125       * @throws  LDAPException  If a problem occurs while reading or parsing the
126       *                         response.
127       */
128      protected GenericResponseProtocolOp(final ASN1StreamReader reader)
129                throws LDAPException
130      {
131        try
132        {
133          type = (byte) reader.peek();
134          final ASN1StreamReaderSequence opSequence = reader.beginSequence();
135          resultCode = reader.readEnumerated();
136    
137          String s = reader.readString();
138          ensureNotNull(s);
139          if (s.length() == 0)
140          {
141            matchedDN = null;
142          }
143          else
144          {
145            matchedDN = s;
146          }
147    
148          s = reader.readString();
149          ensureNotNull(s);
150          if (s.length() == 0)
151          {
152            diagnosticMessage = null;
153          }
154          else
155          {
156            diagnosticMessage = s;
157          }
158    
159          if (opSequence.hasMoreElements())
160          {
161            final ArrayList<String> refs = new ArrayList<String>(1);
162            final ASN1StreamReaderSequence refSequence = reader.beginSequence();
163            while (refSequence.hasMoreElements())
164            {
165              refs.add(reader.readString());
166            }
167            referralURLs = Collections.unmodifiableList(refs);
168          }
169          else
170          {
171            referralURLs = Collections.emptyList();
172          }
173        }
174        catch (Exception e)
175        {
176          debugException(e);
177          throw new LDAPException(ResultCode.DECODING_ERROR,
178               ERR_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)), e);
179        }
180      }
181    
182    
183    
184      /**
185       * Retrieves the result code for this response.
186       *
187       * @return  The result code for this response.
188       */
189      public final int getResultCode()
190      {
191        return resultCode;
192      }
193    
194    
195    
196      /**
197       * Retrieves the matched DN for this response, if any.
198       *
199       * @return  The matched DN for this response, or {@code null} if there is
200       *          no matched DN.
201       */
202      public final String getMatchedDN()
203      {
204        return matchedDN;
205      }
206    
207    
208    
209      /**
210       * Retrieves the diagnostic message for this response, if any.
211       *
212       * @return  The diagnostic message for this response, or {@code null} if there
213       *          is no diagnostic message.
214       */
215      public final String getDiagnosticMessage()
216      {
217        return diagnosticMessage;
218      }
219    
220    
221    
222      /**
223       * Retrieves the list of referral URLs for this response.
224       *
225       * @return  The list of referral URLs for this response, or an empty list
226       *          if there are no referral URLs.
227       */
228      public final List<String> getReferralURLs()
229      {
230        return referralURLs;
231      }
232    
233    
234    
235      /**
236       * {@inheritDoc}
237       */
238      public byte getProtocolOpType()
239      {
240        return type;
241      }
242    
243    
244    
245      /**
246       * {@inheritDoc}
247       */
248      public final void writeTo(final ASN1Buffer buffer)
249      {
250        final ASN1BufferSequence opSequence = buffer.beginSequence(type);
251        buffer.addEnumerated(resultCode);
252        buffer.addOctetString(matchedDN);
253        buffer.addOctetString(diagnosticMessage);
254    
255        if (! referralURLs.isEmpty())
256        {
257          final ASN1BufferSequence refSequence =
258               buffer.beginSequence(TYPE_REFERRALS);
259          for (final String s : referralURLs)
260          {
261            buffer.addOctetString(s);
262          }
263          refSequence.end();
264        }
265        opSequence.end();
266      }
267    
268    
269    
270      /**
271       * Creates a new LDAP result object from this response protocol op.
272       *
273       * @param  controls  The set of controls to include in the LDAP result.  It
274       *                   may be empty or {@code null} if no controls should be
275       *                   included.
276       *
277       * @return  The LDAP result that was created.
278       */
279      public LDAPResult toLDAPResult(final Control... controls)
280      {
281        final String[] refs;
282        if (referralURLs.isEmpty())
283        {
284          refs = NO_STRINGS;
285        }
286        else
287        {
288          refs = new String[referralURLs.size()];
289          referralURLs.toArray(refs);
290        }
291    
292        return new LDAPResult(-1, ResultCode.valueOf(resultCode), diagnosticMessage,
293             matchedDN, refs, controls);
294      }
295    
296    
297    
298      /**
299       * Retrieves a string representation of this protocol op.
300       *
301       * @return  A string representation of this protocol op.
302       */
303      @Override()
304      public final String toString()
305      {
306        final StringBuilder buffer = new StringBuilder();
307        toString(buffer);
308        return buffer.toString();
309      }
310    
311    
312    
313      /**
314       * {@inheritDoc}
315       */
316      public final void toString(final StringBuilder buffer)
317      {
318        buffer.append("ResponseProtocolOp(type=");
319        toHex(type, buffer);
320        buffer.append(", resultCode=");
321        buffer.append(resultCode);
322    
323        if (matchedDN != null)
324        {
325          buffer.append(", matchedDN='");
326          buffer.append(matchedDN);
327          buffer.append('\'');
328        }
329    
330        if (diagnosticMessage != null)
331        {
332          buffer.append(", diagnosticMessage='");
333          buffer.append(diagnosticMessage);
334          buffer.append('\'');
335        }
336    
337        if (! referralURLs.isEmpty())
338        {
339          buffer.append(", referralURLs={");
340    
341          final Iterator<String> iterator = referralURLs.iterator();
342          while (iterator.hasNext())
343          {
344            buffer.append('\'');
345            buffer.append(iterator.next());
346            buffer.append('\'');
347            if (iterator.hasNext())
348            {
349              buffer.append(',');
350            }
351          }
352    
353          buffer.append('}');
354        }
355        buffer.append(')');
356      }
357    }