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 extended response
055     * protocol op, which is used to provide information about the result of
056     * processing a extended request.
057     */
058    public class ExtendedResponseProtocolOp
059           extends ProtocolOp
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = getTracer();
065    
066      // The value for this extended response.
067      private ASN1OctetString value;
068    
069      // The matched DN for this response.
070      private DN matchedDN;
071    
072      // The result code for this response.
073      private int resultCode;
074    
075      // The set of referral URLs for this response.
076      private List<String> referralURLs;
077    
078      // The error message for this response.
079      private Message errorMessage;
080    
081      // The OID for this extended response.
082      private String oid;
083    
084    
085    
086      /**
087       * Creates a new extended response protocol op with the provided result code.
088       *
089       * @param  resultCode  The result code for this response.
090       */
091      public ExtendedResponseProtocolOp(int resultCode)
092      {
093        this.resultCode = resultCode;
094    
095        errorMessage = null;
096        matchedDN    = null;
097        referralURLs = null;
098        oid          = null;
099        value        = null;
100      }
101    
102    
103    
104      /**
105       * Creates a new extended response protocol op with the provided result code
106       * and error message.
107       *
108       * @param  resultCode    The result code for this response.
109       * @param  errorMessage  The error message for this response.
110       */
111      public ExtendedResponseProtocolOp(int resultCode, Message errorMessage)
112      {
113        this.resultCode   = resultCode;
114        this.errorMessage = errorMessage;
115    
116        matchedDN    = null;
117        referralURLs = null;
118        oid          = null;
119        value        = null;
120      }
121    
122    
123    
124      /**
125       * Creates a new extended response protocol op with the provided information.
126       *
127       * @param  resultCode    The result code for this response.
128       * @param  errorMessage  The error message for this response.
129       * @param  matchedDN     The matched DN for this response.
130       * @param  referralURLs  The referral URLs for this response.
131       */
132      public ExtendedResponseProtocolOp(int resultCode, Message errorMessage,
133                                        DN matchedDN, List<String> referralURLs)
134      {
135        this.resultCode   = resultCode;
136        this.errorMessage = errorMessage;
137        this.matchedDN    = matchedDN;
138        this.referralURLs = referralURLs;
139    
140        oid   = null;
141        value = null;
142      }
143    
144    
145    
146      /**
147       * Creates a new extended response protocol op with the provided information.
148       *
149       * @param  resultCode    The result code for this response.
150       * @param  errorMessage  The error message for this response.
151       * @param  matchedDN     The matched DN for this response.
152       * @param  referralURLs  The referral URLs for this response.
153       * @param  oid           The OID for this extended response.
154       * @param  value         The value for this extended response.
155       */
156      public ExtendedResponseProtocolOp(int resultCode, Message errorMessage,
157                                        DN matchedDN, List<String> referralURLs,
158                                        String oid, ASN1OctetString value)
159      {
160        this.resultCode   = resultCode;
161        this.errorMessage = errorMessage;
162        this.matchedDN    = matchedDN;
163        this.referralURLs = referralURLs;
164        this.oid          = oid;
165        this.value        = value;
166      }
167    
168    
169    
170      /**
171       * Retrieves the result code for this response.
172       *
173       * @return  The result code for this response.
174       */
175      public int getResultCode()
176      {
177        return resultCode;
178      }
179    
180    
181    
182      /**
183       * Specifies the result code for this response.
184       *
185       * @param  resultCode  The result code for this response.
186       */
187      public void setResultCode(int resultCode)
188      {
189        this.resultCode = resultCode;
190      }
191    
192    
193    
194      /**
195       * Retrieves the error message for this response.
196       *
197       * @return  The error message for this response, or <CODE>null</CODE> if none
198       *          is available.
199       */
200      public Message getErrorMessage()
201      {
202        return errorMessage;
203      }
204    
205    
206    
207      /**
208       * Specifies the error message for this response.
209       *
210       * @param  errorMessage  The error message for this response.
211       */
212      public void setErrorMessage(Message errorMessage)
213      {
214        this.errorMessage = errorMessage;
215      }
216    
217    
218    
219      /**
220       * Retrieves the matched DN for this response.
221       *
222       * @return  The matched DN for this response, or <CODE>null</CODE> if none is
223       *          available.
224       */
225      public DN getMatchedDN()
226      {
227        return matchedDN;
228      }
229    
230    
231    
232      /**
233       * Specifies the matched DN for this response.
234       *
235       * @param  matchedDN  The matched DN for this response.
236       */
237      public void setMatchedDN(DN matchedDN)
238      {
239        this.matchedDN = matchedDN;
240      }
241    
242    
243    
244      /**
245       * Retrieves the set of referral URLs for this response.
246       *
247       * @return  The set of referral URLs for this response, or <CODE>null</CODE>
248       *          if none are available.
249       */
250      public List<String> getReferralURLs()
251      {
252        return referralURLs;
253      }
254    
255    
256    
257      /**
258       * Specifies the set of referral URLs for this response.
259       *
260       * @param  referralURLs  The set of referral URLs for this response.
261       */
262      public void setReferralURLs(List<String> referralURLs)
263      {
264        this.referralURLs = referralURLs;
265      }
266    
267    
268    
269      /**
270       * Retrieves the OID for this extended response.
271       *
272       * @return  The OID for this extended response, or <CODE>null</CODE> if none
273       *          was provided.
274       */
275      public String getOID()
276      {
277        return oid;
278      }
279    
280    
281    
282      /**
283       * Specifies the OID for this extended response.
284       *
285       * @param  oid  The OID for this extended response.
286       */
287      public void setOID(String oid)
288      {
289        this.oid = oid;
290      }
291    
292    
293    
294      /**
295       * Retrieves the value for this extended response.
296       *
297       * @return  The value for this extended response, or <CODE>null</CODE> if none
298       *          was provided.
299       */
300      public ASN1OctetString getValue()
301      {
302        return value;
303      }
304    
305    
306    
307      /**
308       * Specifies the value for this extended response.
309       *
310       * @param  value  The value for this extended response.
311       */
312      public void setValue(ASN1OctetString value)
313      {
314        this.value = value;
315      }
316    
317    
318    
319      /**
320       * Retrieves the BER type for this protocol op.
321       *
322       * @return  The BER type for this protocol op.
323       */
324      public byte getType()
325      {
326        return OP_TYPE_EXTENDED_RESPONSE;
327      }
328    
329    
330    
331      /**
332       * Retrieves the name for this protocol op type.
333       *
334       * @return  The name for this protocol op type.
335       */
336      public String getProtocolOpName()
337      {
338        return "Extended Response";
339      }
340    
341    
342    
343      /**
344       * Encodes this protocol op to an ASN.1 element suitable for including in an
345       * LDAP message.
346       *
347       * @return  The ASN.1 element containing the encoded protocol op.
348       */
349      public ASN1Element encode()
350      {
351        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(6);
352        elements.add(new ASN1Enumerated(resultCode));
353    
354        if (matchedDN == null)
355        {
356          elements.add(new ASN1OctetString());
357        }
358        else
359        {
360          elements.add(new ASN1OctetString(matchedDN.toString()));
361        }
362    
363        elements.add(new ASN1OctetString(errorMessage));
364    
365        if ((referralURLs != null) && (! referralURLs.isEmpty()))
366        {
367          ArrayList<ASN1Element> referralElements =
368               new ArrayList<ASN1Element>(referralURLs.size());
369    
370          for (String s : referralURLs)
371          {
372            referralElements.add(new ASN1OctetString(s));
373          }
374    
375          elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
376        }
377    
378        if ((oid != null) && (oid.length() > 0))
379        {
380          elements.add(new ASN1OctetString(TYPE_EXTENDED_RESPONSE_OID, oid));
381        }
382    
383        if (value != null)
384        {
385          value.setType(TYPE_EXTENDED_RESPONSE_VALUE);
386          elements.add(value);
387        }
388    
389        return new ASN1Sequence(OP_TYPE_EXTENDED_RESPONSE, elements);
390      }
391    
392    
393    
394      /**
395       * Decodes the provided ASN.1 element as a extended response protocol op.
396       *
397       * @param  element  The ASN.1 element to decode.
398       *
399       * @return  The decoded extended response protocol op.
400       *
401       * @throws  LDAPException  If a problem occurs while attempting to decode the
402       *                         ASN.1 element to a protocol op.
403       */
404      public static ExtendedResponseProtocolOp decodeExtendedResponse(ASN1Element
405                                                                           element)
406             throws LDAPException
407      {
408        ArrayList<ASN1Element> elements;
409        try
410        {
411          elements = element.decodeAsSequence().elements();
412        }
413        catch (Exception e)
414        {
415          if (debugEnabled())
416          {
417            TRACER.debugCaught(DebugLogLevel.ERROR, e);
418          }
419    
420          Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
421          throw new LDAPException(PROTOCOL_ERROR, message, e);
422        }
423    
424    
425        int numElements = elements.size();
426        if ((numElements < 3) || (numElements > 6))
427        {
428          Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_ELEMENT_COUNT.
429              get(numElements);
430          throw new LDAPException(PROTOCOL_ERROR, message);
431        }
432    
433    
434        int resultCode;
435        try
436        {
437          resultCode = elements.get(0).decodeAsInteger().intValue();
438        }
439        catch (Exception e)
440        {
441          if (debugEnabled())
442          {
443            TRACER.debugCaught(DebugLogLevel.ERROR, e);
444          }
445    
446          Message message =
447              ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
448          throw new LDAPException(PROTOCOL_ERROR, message, e);
449        }
450    
451    
452        DN matchedDN;
453        try
454        {
455          String dnString = elements.get(1).decodeAsOctetString().stringValue();
456          if (dnString.length() == 0)
457          {
458            matchedDN = null;
459          }
460          else
461          {
462            matchedDN = DN.decode(dnString);
463          }
464        }
465        catch (Exception e)
466        {
467          if (debugEnabled())
468          {
469            TRACER.debugCaught(DebugLogLevel.ERROR, e);
470          }
471    
472          Message message =
473              ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
474          throw new LDAPException(PROTOCOL_ERROR, message, e);
475        }
476    
477    
478        Message errorMessage;
479        try
480        {
481          errorMessage = Message.raw(
482                  elements.get(2).decodeAsOctetString().stringValue());
483          if (errorMessage.length() == 0)
484          {
485            errorMessage = null;
486          }
487        }
488        catch (Exception e)
489        {
490          if (debugEnabled())
491          {
492            TRACER.debugCaught(DebugLogLevel.ERROR, e);
493          }
494    
495          Message message =
496              ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
497          throw new LDAPException(PROTOCOL_ERROR, message, e);
498        }
499    
500    
501        ArrayList<String> referralURLs = null;
502        String            oid          = null;
503        ASN1OctetString   value        = null;
504        for (int i=3; i < elements.size(); i++)
505        {
506          element = elements.get(i);
507          switch (element.getType())
508          {
509            case TYPE_REFERRAL_SEQUENCE:
510              try
511              {
512                ArrayList<ASN1Element> referralElements =
513                     element.decodeAsSequence().elements();
514                referralURLs = new ArrayList<String>(referralElements.size());
515    
516                for (ASN1Element e : referralElements)
517                {
518                  referralURLs.add(e.decodeAsOctetString().stringValue());
519                }
520              }
521              catch (Exception e)
522              {
523                if (debugEnabled())
524                {
525                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
526                }
527    
528                Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_REFERRALS.get(
529                    String.valueOf(e));
530                throw new LDAPException(PROTOCOL_ERROR, message, e);
531              }
532    
533              break;
534            case TYPE_EXTENDED_RESPONSE_OID:
535              try
536              {
537                oid = element.decodeAsOctetString().stringValue();
538              }
539              catch (Exception e)
540              {
541                if (debugEnabled())
542                {
543                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
544                }
545    
546                Message message =
547                    ERR_LDAP_EXTENDED_RESULT_DECODE_OID.get(String.valueOf(e));
548                throw new LDAPException(PROTOCOL_ERROR, message, e);
549              }
550    
551              break;
552            case TYPE_EXTENDED_RESPONSE_VALUE:
553              try
554              {
555                value = element.decodeAsOctetString();
556              }
557              catch (Exception e)
558              {
559                if (debugEnabled())
560                {
561                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
562                }
563    
564                Message message =
565                    ERR_LDAP_EXTENDED_RESULT_DECODE_VALUE.get(String.valueOf(e));
566                throw new LDAPException(PROTOCOL_ERROR, message, e);
567              }
568    
569              break;
570            default:
571              Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_TYPE.get(
572                  element.getType());
573              throw new LDAPException(PROTOCOL_ERROR, message);
574          }
575        }
576    
577    
578        return new ExtendedResponseProtocolOp(resultCode, errorMessage, matchedDN,
579                                              referralURLs, oid, value);
580      }
581    
582    
583    
584      /**
585       * Appends a string representation of this LDAP protocol op to the provided
586       * buffer.
587       *
588       * @param  buffer  The buffer to which the string should be appended.
589       */
590      public void toString(StringBuilder buffer)
591      {
592        buffer.append("ExtendedResponse(resultCode=");
593        buffer.append(resultCode);
594    
595        if ((errorMessage != null) && (errorMessage.length() > 0))
596        {
597          buffer.append(", errorMessage=");
598          buffer.append(errorMessage);
599        }
600    
601        if (matchedDN != null)
602        {
603          buffer.append(", matchedDN=");
604          buffer.append(matchedDN.toString());
605        }
606    
607        if ((referralURLs != null) && (! referralURLs.isEmpty()))
608        {
609          buffer.append(", referralURLs={");
610    
611          Iterator<String> iterator = referralURLs.iterator();
612          buffer.append(iterator.next());
613    
614          while (iterator.hasNext())
615          {
616            buffer.append(", ");
617            buffer.append(iterator.next());
618          }
619    
620          buffer.append("}");
621        }
622    
623        if ((oid != null) && (oid.length() > 0))
624        {
625          buffer.append(", oid=");
626          buffer.append(oid);
627        }
628    
629        if (value != null)
630        {
631          buffer.append(", value=");
632          value.toString(buffer);
633        }
634    
635        buffer.append(")");
636      }
637    
638    
639    
640      /**
641       * Appends a multi-line string representation of this LDAP protocol op to the
642       * provided buffer.
643       *
644       * @param  buffer  The buffer to which the information should be appended.
645       * @param  indent  The number of spaces from the margin that the lines should
646       *                 be indented.
647       */
648      public void toString(StringBuilder buffer, int indent)
649      {
650        StringBuilder indentBuf = new StringBuilder(indent);
651        for (int i=0 ; i < indent; i++)
652        {
653          indentBuf.append(' ');
654        }
655    
656        buffer.append(indentBuf);
657        buffer.append("Extended Response");
658        buffer.append(EOL);
659    
660        buffer.append(indentBuf);
661        buffer.append("  Result Code:  ");
662        buffer.append(resultCode);
663        buffer.append(EOL);
664    
665        if (errorMessage != null)
666        {
667          buffer.append(indentBuf);
668          buffer.append("  Error Message:  ");
669          buffer.append(errorMessage);
670          buffer.append(EOL);
671        }
672    
673        if (matchedDN != null)
674        {
675          buffer.append(indentBuf);
676          buffer.append("  Matched DN:  ");
677          matchedDN.toString(buffer);
678          buffer.append(EOL);
679        }
680    
681        if ((referralURLs != null) && (! referralURLs.isEmpty()))
682        {
683          buffer.append(indentBuf);
684          buffer.append("  Referral URLs:  ");
685          buffer.append(EOL);
686    
687          for (String s : referralURLs)
688          {
689            buffer.append(indentBuf);
690            buffer.append("  ");
691            buffer.append(s);
692            buffer.append(EOL);
693          }
694        }
695    
696        if ((oid != null) && (oid.length() > 0))
697        {
698          buffer.append(indentBuf);
699          buffer.append("  Response OID:  ");
700          buffer.append(oid);
701          buffer.append(EOL);
702        }
703    
704        if (value != null)
705        {
706          buffer.append(indentBuf);
707          buffer.append("  Response Value:  ");
708          value.toString(buffer);
709          buffer.append(EOL);
710        }
711      }
712    }
713