001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.protocols.ldap;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    import java.util.Iterator;
034    import java.util.List;
035    
036    import org.opends.server.protocols.asn1.ASN1Element;
037    import org.opends.server.protocols.asn1.ASN1Enumerated;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.protocols.asn1.ASN1Sequence;
040    import org.opends.server.types.DebugLogLevel;
041    import org.opends.server.types.DN;
042    import org.opends.server.types.LDAPException;
043    
044    import static org.opends.server.loggers.debug.DebugLogger.*;
045    import org.opends.server.loggers.debug.DebugTracer;
046    import static org.opends.messages.ProtocolMessages.*;
047    import static org.opends.server.protocols.ldap.LDAPConstants.*;
048    import static org.opends.server.protocols.ldap.LDAPResultCode.*;
049    import static org.opends.server.util.ServerConstants.*;
050    
051    
052    
053    /**
054     * This class defines the structures and methods for an LDAP search result done
055     * protocol op, which is used to provide information about the result of
056     * processing a search request.
057     */
058    public class SearchResultDoneProtocolOp
059           extends ProtocolOp
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = getTracer();
065    
066      // The matched DN for this response.
067      private DN matchedDN;
068    
069      // The result code for this response.
070      private int resultCode;
071    
072      // The set of referral URLs for this response.
073      private List<String> referralURLs;
074    
075      // The error message for this response.
076      private Message errorMessage;
077    
078    
079    
080      /**
081       * Creates a new search result done protocol op with the provided result code.
082       *
083       * @param  resultCode  The result code for this response.
084       */
085      public SearchResultDoneProtocolOp(int resultCode)
086      {
087        this.resultCode = resultCode;
088    
089        errorMessage = null;
090        matchedDN = null;
091        referralURLs = null;
092      }
093    
094    
095    
096      /**
097       * Creates a new search result done protocol op with the provided result code
098       * and error message.
099       *
100       * @param  resultCode    The result code for this response.
101       * @param  errorMessage  The error message for this response.
102       */
103      public SearchResultDoneProtocolOp(int resultCode, Message errorMessage)
104      {
105        this.resultCode   = resultCode;
106        this.errorMessage = errorMessage;
107    
108        matchedDN    = null;
109        referralURLs = null;
110      }
111    
112    
113    
114      /**
115       * Creates a new search result done protocol op with the provided information.
116       *
117       * @param  resultCode    The result code for this response.
118       * @param  errorMessage  The error message for this response.
119       * @param  matchedDN     The matched DN for this response.
120       * @param  referralURLs  The referral URLs for this response.
121       */
122      public SearchResultDoneProtocolOp(int resultCode, Message errorMessage,
123                                        DN matchedDN, List<String> referralURLs)
124      {
125        this.resultCode   = resultCode;
126        this.errorMessage = errorMessage;
127        this.matchedDN    = matchedDN;
128        this.referralURLs = referralURLs;
129      }
130    
131    
132    
133      /**
134       * Retrieves the result code for this response.
135       *
136       * @return  The result code for this response.
137       */
138      public int getResultCode()
139      {
140        return resultCode;
141      }
142    
143    
144    
145      /**
146       * Specifies the result code for this response.
147       *
148       * @param  resultCode  The result code for this response.
149       */
150      public void setResultCode(int resultCode)
151      {
152        this.resultCode = resultCode;
153      }
154    
155    
156    
157      /**
158       * Retrieves the error message for this response.
159       *
160       * @return  The error message for this response, or <CODE>null</CODE> if none
161       *          is available.
162       */
163      public Message getErrorMessage()
164      {
165        return errorMessage;
166      }
167    
168    
169    
170      /**
171       * Specifies the error message for this response.
172       *
173       * @param  errorMessage  The error message for this response.
174       */
175      public void setErrorMessage(Message errorMessage)
176      {
177        this.errorMessage = errorMessage;
178      }
179    
180    
181    
182      /**
183       * Retrieves the matched DN for this response.
184       *
185       * @return  The matched DN for this response, or <CODE>null</CODE> if none is
186       *          available.
187       */
188      public DN getMatchedDN()
189      {
190        return matchedDN;
191      }
192    
193    
194    
195      /**
196       * Specifies the matched DN for this response.
197       *
198       * @param  matchedDN  The matched DN for this response.
199       */
200      public void setMatchedDN(DN matchedDN)
201      {
202        this.matchedDN = matchedDN;
203      }
204    
205    
206    
207      /**
208       * Retrieves the set of referral URLs for this response.
209       *
210       * @return  The set of referral URLs for this response, or <CODE>null</CODE>
211       *          if none are available.
212       */
213      public List<String> getReferralURLs()
214      {
215        return referralURLs;
216      }
217    
218    
219    
220      /**
221       * Specifies the set of referral URLs for this response.
222       *
223       * @param  referralURLs  The set of referral URLs for this response.
224       */
225      public void setReferralURLs(List<String> referralURLs)
226      {
227        this.referralURLs = referralURLs;
228      }
229    
230    
231    
232      /**
233       * Retrieves the BER type for this protocol op.
234       *
235       * @return  The BER type for this protocol op.
236       */
237      public byte getType()
238      {
239        return OP_TYPE_SEARCH_RESULT_DONE;
240      }
241    
242    
243    
244      /**
245       * Retrieves the name for this protocol op type.
246       *
247       * @return  The name for this protocol op type.
248       */
249      public String getProtocolOpName()
250      {
251        return "Search Result Done";
252      }
253    
254    
255    
256      /**
257       * Encodes this protocol op to an ASN.1 element suitable for including in an
258       * LDAP message.
259       *
260       * @return  The ASN.1 element containing the encoded protocol op.
261       */
262      public ASN1Element encode()
263      {
264        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
265        elements.add(new ASN1Enumerated(resultCode));
266    
267        if (matchedDN == null)
268        {
269          elements.add(new ASN1OctetString());
270        }
271        else
272        {
273          elements.add(new ASN1OctetString(matchedDN.toString()));
274        }
275    
276        if (errorMessage == null)
277        {
278          elements.add(new ASN1OctetString());
279        }
280        else
281        {
282          elements.add(new ASN1OctetString(errorMessage));
283        }
284    
285        if ((referralURLs != null) && (! referralURLs.isEmpty()))
286        {
287          ArrayList<ASN1Element> referralElements =
288               new ArrayList<ASN1Element>(referralURLs.size());
289    
290          for (String s : referralURLs)
291          {
292            referralElements.add(new ASN1OctetString(s));
293          }
294    
295          elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
296        }
297    
298        return new ASN1Sequence(OP_TYPE_SEARCH_RESULT_DONE, elements);
299      }
300    
301    
302    
303      /**
304       * Decodes the provided ASN.1 element as a search result done protocol op.
305       *
306       * @param  element  The ASN.1 element to decode.
307       *
308       * @return  The decoded search result done protocol op.
309       *
310       * @throws  LDAPException  If a problem occurs while attempting to decode the
311       *                         ASN.1 element to a protocol op.
312       */
313      public static SearchResultDoneProtocolOp decodeSearchDone(ASN1Element
314                                                                      element)
315             throws LDAPException
316      {
317        ArrayList<ASN1Element> elements;
318        try
319        {
320          elements = element.decodeAsSequence().elements();
321        }
322        catch (Exception e)
323        {
324          if (debugEnabled())
325          {
326            TRACER.debugCaught(DebugLogLevel.ERROR, e);
327          }
328    
329          Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
330          throw new LDAPException(PROTOCOL_ERROR, message, e);
331        }
332    
333    
334        int numElements = elements.size();
335        if ((numElements < 3) || (numElements > 4))
336        {
337          Message message =
338              ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
339          throw new LDAPException(PROTOCOL_ERROR, message);
340        }
341    
342    
343        int resultCode;
344        try
345        {
346          resultCode = elements.get(0).decodeAsInteger().intValue();
347        }
348        catch (Exception e)
349        {
350          if (debugEnabled())
351          {
352            TRACER.debugCaught(DebugLogLevel.ERROR, e);
353          }
354    
355          Message message =
356              ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
357          throw new LDAPException(PROTOCOL_ERROR, message, e);
358        }
359    
360    
361        DN matchedDN;
362        try
363        {
364          String dnString = elements.get(1).decodeAsOctetString().stringValue();
365          if (dnString.length() == 0)
366          {
367            matchedDN = null;
368          }
369          else
370          {
371            matchedDN = DN.decode(dnString);
372          }
373        }
374        catch (Exception e)
375        {
376          if (debugEnabled())
377          {
378            TRACER.debugCaught(DebugLogLevel.ERROR, e);
379          }
380    
381          Message message =
382              ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
383          throw new LDAPException(PROTOCOL_ERROR, message, e);
384        }
385    
386    
387        Message errorMessage;
388        try
389        {
390          errorMessage =
391                  Message.raw(elements.get(2).decodeAsOctetString().stringValue());
392          if (errorMessage.length() == 0)
393          {
394            errorMessage = null;
395          }
396        }
397        catch (Exception e)
398        {
399          if (debugEnabled())
400          {
401            TRACER.debugCaught(DebugLogLevel.ERROR, e);
402          }
403    
404          Message message =
405              ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
406          throw new LDAPException(PROTOCOL_ERROR, message, e);
407        }
408    
409    
410        ArrayList<String> referralURLs;
411        if (numElements == 3)
412        {
413          referralURLs = null;
414        }
415        else
416        {
417          try
418          {
419            ArrayList<ASN1Element> referralElements =
420                 elements.get(3).decodeAsSequence().elements();
421            referralURLs = new ArrayList<String>(referralElements.size());
422    
423            for (ASN1Element e : referralElements)
424            {
425              referralURLs.add(e.decodeAsOctetString().stringValue());
426            }
427          }
428          catch (Exception e)
429          {
430            if (debugEnabled())
431            {
432              TRACER.debugCaught(DebugLogLevel.ERROR, e);
433            }
434    
435            Message message =
436                ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
437            throw new LDAPException(PROTOCOL_ERROR, message, e);
438          }
439        }
440    
441    
442        return new SearchResultDoneProtocolOp(resultCode, errorMessage, matchedDN,
443                                              referralURLs);
444      }
445    
446    
447    
448      /**
449       * Appends a string representation of this LDAP protocol op to the provided
450       * buffer.
451       *
452       * @param  buffer  The buffer to which the string should be appended.
453       */
454      public void toString(StringBuilder buffer)
455      {
456        buffer.append("SearchResultDone(resultCode=");
457        buffer.append(resultCode);
458    
459        if ((errorMessage != null) && (errorMessage.length() > 0))
460        {
461          buffer.append(", errorMessage=");
462          buffer.append(errorMessage);
463        }
464    
465        if (matchedDN != null)
466        {
467          buffer.append(", matchedDN=");
468          buffer.append(matchedDN.toString());
469        }
470    
471        if ((referralURLs != null) && (! referralURLs.isEmpty()))
472        {
473          buffer.append(", referralURLs={");
474    
475          Iterator<String> iterator = referralURLs.iterator();
476          buffer.append(iterator.next());
477    
478          while (iterator.hasNext())
479          {
480            buffer.append(", ");
481            buffer.append(iterator.next());
482          }
483    
484          buffer.append("}");
485        }
486    
487        buffer.append(")");
488      }
489    
490    
491    
492      /**
493       * Appends a multi-line string representation of this LDAP protocol op to the
494       * provided buffer.
495       *
496       * @param  buffer  The buffer to which the information should be appended.
497       * @param  indent  The number of spaces from the margin that the lines should
498       *                 be indented.
499       */
500      public void toString(StringBuilder buffer, int indent)
501      {
502        StringBuilder indentBuf = new StringBuilder(indent);
503        for (int i=0 ; i < indent; i++)
504        {
505          indentBuf.append(' ');
506        }
507    
508        buffer.append(indentBuf);
509        buffer.append("Search Result Done");
510        buffer.append(EOL);
511    
512        buffer.append(indentBuf);
513        buffer.append("  Result Code:  ");
514        buffer.append(resultCode);
515        buffer.append(EOL);
516    
517        if (errorMessage != null)
518        {
519          buffer.append(indentBuf);
520          buffer.append("  Error Message:  ");
521          buffer.append(errorMessage);
522          buffer.append(EOL);
523        }
524    
525        if (matchedDN != null)
526        {
527          buffer.append(indentBuf);
528          buffer.append("  Matched DN:  ");
529          matchedDN.toString(buffer);
530          buffer.append(EOL);
531        }
532    
533        if ((referralURLs != null) && (! referralURLs.isEmpty()))
534        {
535          buffer.append(indentBuf);
536          buffer.append("  Referral URLs:  ");
537          buffer.append(EOL);
538    
539          for (String s : referralURLs)
540          {
541            buffer.append(indentBuf);
542            buffer.append("  ");
543            buffer.append(s);
544            buffer.append(EOL);
545          }
546        }
547      }
548    }
549