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
035 import org.opends.server.api.ProtocolElement;
036 import org.opends.server.protocols.asn1.ASN1Element;
037 import org.opends.server.protocols.asn1.ASN1Integer;
038 import org.opends.server.protocols.asn1.ASN1Sequence;
039 import org.opends.server.types.DebugLogLevel;
040 import org.opends.server.types.LDAPException;
041
042 import static org.opends.server.loggers.debug.DebugLogger.*;
043 import org.opends.server.loggers.debug.DebugTracer;
044 import static org.opends.messages.ProtocolMessages.*;
045 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
046 import static org.opends.server.util.ServerConstants.*;
047
048
049 /**
050 * This class defines the data structures and methods to use when interacting
051 * with an LDAP message, which is the basic envelope used to hold LDAP requests
052 * and responses.
053 */
054 public class LDAPMessage
055 implements ProtocolElement
056 {
057 /**
058 * The tracer object for the debug logger.
059 */
060 private static final DebugTracer TRACER = getTracer();
061
062 // The set of controls for this LDAP message.
063 private ArrayList<LDAPControl> controls;
064
065 // The message ID for this LDAP message.
066 private int messageID;
067
068 // The protocol op for this LDAP message.
069 private ProtocolOp protocolOp;
070
071
072
073 /**
074 * Creates a new LDAP message with the provided message ID and protocol op but
075 * no controls.
076 *
077 * @param messageID The message ID for this LDAP message.
078 * @param protocolOp The protocol op for this LDAP message.
079 */
080 public LDAPMessage(int messageID, ProtocolOp protocolOp)
081 {
082 this.messageID = messageID;
083 this.protocolOp = protocolOp;
084
085 controls = new ArrayList<LDAPControl>(0);
086 }
087
088
089
090 /**
091 * Creates a new LDAP message with the provided message ID, protocol op, and
092 * set of controls.
093 *
094 * @param messageID The message ID for this LDAP message.
095 * @param protocolOp The protocol op for this LDAP message.
096 * @param controls The set of controls for this LDAP message.
097 */
098 public LDAPMessage(int messageID, ProtocolOp protocolOp,
099 ArrayList<LDAPControl> controls)
100 {
101 this.messageID = messageID;
102 this.protocolOp = protocolOp;
103
104 if (controls == null)
105 {
106 this.controls = new ArrayList<LDAPControl>(0);
107 }
108 else
109 {
110 this.controls = controls;
111 }
112 }
113
114
115
116 /**
117 * Retrieves the message ID for this LDAP message.
118 *
119 * @return The message ID for this LDAP message.
120 */
121 public int getMessageID()
122 {
123 return messageID;
124 }
125
126
127
128 /**
129 * Specifies the message ID for this LDAP message.
130 *
131 * @param messageID The message ID for this LDAP message.
132 */
133 public void setMessageID(int messageID)
134 {
135 this.messageID = messageID;
136 }
137
138
139
140 /**
141 * Retrieves the protocol op for this LDAP message.
142 *
143 * @return The protocol op for this LDAP message.
144 */
145 public ProtocolOp getProtocolOp()
146 {
147 return protocolOp;
148 }
149
150
151
152 /**
153 * Retrieves the protocol op type for this LDAP message.
154 *
155 * @return The protocol op type for this LDAP message.
156 */
157 public byte getProtocolOpType()
158 {
159 return protocolOp.getType();
160 }
161
162
163
164 /**
165 * Retrieves the protocol op name for this LDAP message.
166 *
167 * @return The protocol op name for this LDAP message.
168 */
169 public String getProtocolOpName()
170 {
171 return protocolOp.getProtocolOpName();
172 }
173
174
175
176 /**
177 * Retrieves the protocol op for this LDAP message as an abandon request
178 * protocol op.
179 *
180 * @return The protocol op for this LDAP message as an abandon request
181 * protocol op.
182 *
183 * @throws ClassCastException If the protocol op is not an abandon request
184 * protocol op.
185 */
186 public AbandonRequestProtocolOp getAbandonRequestProtocolOp()
187 throws ClassCastException
188 {
189 return (AbandonRequestProtocolOp) protocolOp;
190 }
191
192
193
194 /**
195 * Retrieves the protocol op for this LDAP message as an add request protocol
196 * op.
197 *
198 * @return The protocol op for this LDAP message as an add request protocol
199 * op.
200 *
201 * @throws ClassCastException If the protocol op is not an add request
202 * protocol op.
203 */
204 public AddRequestProtocolOp getAddRequestProtocolOp()
205 throws ClassCastException
206 {
207 return (AddRequestProtocolOp) protocolOp;
208 }
209
210
211
212 /**
213 * Retrieves the protocol op for this LDAP message as an add response protocol
214 * op.
215 *
216 * @return The protocol op for this LDAP message as an add response protocol
217 * op.
218 *
219 * @throws ClassCastException If the protocol op is not an add response
220 * protocol op.
221 */
222 public AddResponseProtocolOp getAddResponseProtocolOp()
223 throws ClassCastException
224 {
225 return (AddResponseProtocolOp) protocolOp;
226 }
227
228
229
230 /**
231 * Retrieves the protocol op for this LDAP message as a bind request
232 * protocol op.
233 *
234 * @return The protocol op for this LDAP message as a bind request
235 * protocol op.
236 *
237 * @throws ClassCastException If the protocol op is not a bind request
238 * protocol op.
239 */
240 public BindRequestProtocolOp getBindRequestProtocolOp()
241 throws ClassCastException
242 {
243 return (BindRequestProtocolOp) protocolOp;
244 }
245
246
247
248 /**
249 * Retrieves the protocol op for this LDAP message as a bind response
250 * protocol op.
251 *
252 * @return The protocol op for this LDAP message as a bind response
253 * protocol op.
254 *
255 * @throws ClassCastException If the protocol op is not a bind response
256 * protocol op.
257 */
258 public BindResponseProtocolOp getBindResponseProtocolOp()
259 throws ClassCastException
260 {
261 return (BindResponseProtocolOp) protocolOp;
262 }
263
264
265
266 /**
267 * Retrieves the protocol op for this LDAP message as a compare request
268 * protocol op.
269 *
270 * @return The protocol op for this LDAP message as a compare request
271 * protocol op.
272 *
273 * @throws ClassCastException If the protocol op is not a compare request
274 * protocol op.
275 */
276 public CompareRequestProtocolOp getCompareRequestProtocolOp()
277 throws ClassCastException
278 {
279 return (CompareRequestProtocolOp) protocolOp;
280 }
281
282
283
284 /**
285 * Retrieves the protocol op for this LDAP message as a compare response
286 * protocol op.
287 *
288 * @return The protocol op for this LDAP message as a compare response
289 * protocol op.
290 *
291 * @throws ClassCastException If the protocol op is not a compare response
292 * protocol op.
293 */
294 public CompareResponseProtocolOp getCompareResponseProtocolOp()
295 throws ClassCastException
296 {
297 return (CompareResponseProtocolOp) protocolOp;
298 }
299
300
301
302 /**
303 * Retrieves the protocol op for this LDAP message as a delete request
304 * protocol op.
305 *
306 * @return The protocol op for this LDAP message as a delete request
307 * protocol op.
308 *
309 * @throws ClassCastException If the protocol op is not a delete request
310 * protocol op.
311 */
312 public DeleteRequestProtocolOp getDeleteRequestProtocolOp()
313 throws ClassCastException
314 {
315 return (DeleteRequestProtocolOp) protocolOp;
316 }
317
318
319
320 /**
321 * Retrieves the protocol op for this LDAP message as a delete response
322 * protocol op.
323 *
324 * @return The protocol op for this LDAP message as a delete response
325 * protocol op.
326 *
327 * @throws ClassCastException If the protocol op is not a delete response
328 * protocol op.
329 */
330 public DeleteResponseProtocolOp getDeleteResponseProtocolOp()
331 throws ClassCastException
332 {
333 return (DeleteResponseProtocolOp) protocolOp;
334 }
335
336
337
338 /**
339 * Retrieves the protocol op for this LDAP message as an extended request
340 * protocol op.
341 *
342 * @return The protocol op for this LDAP message as an extended request
343 * protocol op.
344 *
345 * @throws ClassCastException If the protocol op is not an extended request
346 * protocol op.
347 */
348 public ExtendedRequestProtocolOp getExtendedRequestProtocolOp()
349 throws ClassCastException
350 {
351 return (ExtendedRequestProtocolOp) protocolOp;
352 }
353
354
355
356 /**
357 * Retrieves the protocol op for this LDAP message as an extended response
358 * protocol op.
359 *
360 * @return The protocol op for this LDAP message as an extended response
361 * protocol op.
362 *
363 * @throws ClassCastException If the protocol op is not an extended response
364 * protocol op.
365 */
366 public ExtendedResponseProtocolOp getExtendedResponseProtocolOp()
367 throws ClassCastException
368 {
369 return (ExtendedResponseProtocolOp) protocolOp;
370 }
371
372
373
374 /**
375 * Retrieves the protocol op for this LDAP message as a modify request
376 * protocol op.
377 *
378 * @return The protocol op for this LDAP message as a modify request
379 * protocol op.
380 *
381 * @throws ClassCastException If the protocol op is not a modify request
382 * protocol op.
383 */
384 public ModifyRequestProtocolOp getModifyRequestProtocolOp()
385 throws ClassCastException
386 {
387 return (ModifyRequestProtocolOp) protocolOp;
388 }
389
390
391
392 /**
393 * Retrieves the protocol op for this LDAP message as a modify response
394 * protocol op.
395 *
396 * @return The protocol op for this LDAP message as a modify response
397 * protocol op.
398 *
399 * @throws ClassCastException If the protocol op is not a modify response
400 * protocol op.
401 */
402 public ModifyResponseProtocolOp getModifyResponseProtocolOp()
403 throws ClassCastException
404 {
405 return (ModifyResponseProtocolOp) protocolOp;
406 }
407
408
409
410 /**
411 * Retrieves the protocol op for this LDAP message as a modify DN request
412 * protocol op.
413 *
414 * @return The protocol op for this LDAP message as a modify DN request
415 * protocol op.
416 *
417 * @throws ClassCastException If the protocol op is not a modify DN request
418 * protocol op.
419 */
420 public ModifyDNRequestProtocolOp getModifyDNRequestProtocolOp()
421 throws ClassCastException
422 {
423 return (ModifyDNRequestProtocolOp) protocolOp;
424 }
425
426
427
428 /**
429 * Retrieves the protocol op for this LDAP message as a modify DN response
430 * protocol op.
431 *
432 * @return The protocol op for this LDAP message as a modify DN response
433 * protocol op.
434 *
435 * @throws ClassCastException If the protocol op is not a modify DN response
436 * protocol op.
437 */
438 public ModifyDNResponseProtocolOp getModifyDNResponseProtocolOp()
439 throws ClassCastException
440 {
441 return (ModifyDNResponseProtocolOp) protocolOp;
442 }
443
444
445
446 /**
447 * Retrieves the protocol op for this LDAP message as a search request
448 * protocol op.
449 *
450 * @return The protocol op for this LDAP message as a search request
451 * protocol op.
452 *
453 * @throws ClassCastException If the protocol op is not a search request
454 * protocol op.
455 */
456 public SearchRequestProtocolOp getSearchRequestProtocolOp()
457 throws ClassCastException
458 {
459 return (SearchRequestProtocolOp) protocolOp;
460 }
461
462
463
464 /**
465 * Retrieves the protocol op for this LDAP message as a search result done
466 * protocol op.
467 *
468 * @return The protocol op for this LDAP message as a search result done
469 * protocol op.
470 *
471 * @throws ClassCastException If the protocol op is not a search result done
472 * protocol op.
473 */
474 public SearchResultDoneProtocolOp getSearchResultDoneProtocolOp()
475 throws ClassCastException
476 {
477 return (SearchResultDoneProtocolOp) protocolOp;
478 }
479
480
481
482 /**
483 * Retrieves the protocol op for this LDAP message as a search result entry
484 * protocol op.
485 *
486 * @return The protocol op for this LDAP message as a search result entry
487 * protocol op.
488 *
489 * @throws ClassCastException If the protocol op is not a search result
490 * entry protocol op.
491 */
492 public SearchResultEntryProtocolOp getSearchResultEntryProtocolOp()
493 throws ClassCastException
494 {
495 return (SearchResultEntryProtocolOp) protocolOp;
496 }
497
498
499
500 /**
501 * Retrieves the protocol op for this LDAP message as a search result
502 * reference protocol op.
503 *
504 * @return The protocol op for this LDAP message as a search result reference
505 * protocol op.
506 *
507 * @throws ClassCastException If the protocol op is not a search result
508 * reference protocol op.
509 */
510 public SearchResultReferenceProtocolOp getSearchResultReferenceProtocolOp()
511 throws ClassCastException
512 {
513 return (SearchResultReferenceProtocolOp) protocolOp;
514 }
515
516
517
518 /**
519 * Retrieves the protocol op for this LDAP message as an unbind request
520 * protocol op.
521 *
522 * @return The protocol op for this LDAP message as an unbind request
523 * protocol op.
524 *
525 * @throws ClassCastException If the protocol op is not an unbind request
526 * protocol op.
527 */
528 public UnbindRequestProtocolOp getUnbindRequestProtocolOp()
529 throws ClassCastException
530 {
531 return (UnbindRequestProtocolOp) protocolOp;
532 }
533
534
535
536 /**
537 * Specifies the protocol op for this LDAP message.
538 *
539 * @param protocolOp The protocol op for this LDAP message.
540 */
541 public void setProtocolOp(ProtocolOp protocolOp)
542 {
543 this.protocolOp = protocolOp;
544 }
545
546
547
548 /**
549 * Retrieves the set of controls for this LDAP message. It may be modified by
550 * the caller.
551 *
552 * @return The set of controls for this LDAP message.
553 */
554 public ArrayList<LDAPControl> getControls()
555 {
556 return controls;
557 }
558
559
560
561 /**
562 * Encodes this LDAP message to an ASN.1 element.
563 *
564 * @return The ASN.1 element containing the encoded LDAP message.
565 */
566 public ASN1Element encode()
567 {
568 ArrayList<ASN1Element> messageElements = new ArrayList<ASN1Element>(3);
569 messageElements.add(new ASN1Integer(messageID));
570 messageElements.add(protocolOp.encode());
571
572 if (! controls.isEmpty())
573 {
574 messageElements.add(LDAPControl.encodeControls(controls));
575 }
576
577 return new ASN1Sequence(messageElements);
578 }
579
580
581
582 /**
583 * Decodes the provided ASN.1 sequence as an LDAP message.
584 *
585 * @param messageSequence The ASN.1 sequence to decode as an LDAP message.
586 *
587 * @return The decoded LDAP message.
588 *
589 * @throws LDAPException If a problem occurs while attempting to decode the
590 * LDAP message.
591 */
592 public static LDAPMessage decode(ASN1Sequence messageSequence)
593 throws LDAPException
594 {
595 if (messageSequence == null)
596 {
597 Message message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
598 throw new LDAPException(PROTOCOL_ERROR, message);
599 }
600
601 ArrayList<ASN1Element> elements = messageSequence.elements();
602 int numElements = elements.size();
603 if ((numElements < 2) || (numElements > 3))
604 {
605 Message message =
606 ERR_LDAP_MESSAGE_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
607 throw new LDAPException(PROTOCOL_ERROR, message);
608 }
609
610
611 int messageID;
612 try
613 {
614 messageID = elements.get(0).decodeAsInteger().intValue();
615 }
616 catch (Exception e)
617 {
618 if (debugEnabled())
619 {
620 TRACER.debugCaught(DebugLogLevel.ERROR, e);
621 }
622
623 Message message =
624 ERR_LDAP_MESSAGE_DECODE_MESSAGE_ID.get(String.valueOf(e));
625 throw new LDAPException(PROTOCOL_ERROR, message, e);
626 }
627
628
629 ProtocolOp protocolOp;
630 try
631 {
632 protocolOp = ProtocolOp.decode(elements.get(1));
633 }
634 catch (Exception e)
635 {
636 if (debugEnabled())
637 {
638 TRACER.debugCaught(DebugLogLevel.ERROR, e);
639 }
640
641 Message message =
642 ERR_LDAP_MESSAGE_DECODE_PROTOCOL_OP.get(String.valueOf(e));
643 throw new LDAPException(PROTOCOL_ERROR, message, e);
644 }
645
646
647 ArrayList<LDAPControl> controls;
648 if (numElements == 3)
649 {
650 try
651 {
652 controls = LDAPControl.decodeControls(elements.get(2));
653 }
654 catch (Exception e)
655 {
656 if (debugEnabled())
657 {
658 TRACER.debugCaught(DebugLogLevel.ERROR, e);
659 }
660
661 Message message =
662 ERR_LDAP_MESSAGE_DECODE_CONTROLS.get(String.valueOf(e));
663 throw new LDAPException(PROTOCOL_ERROR, message, e);
664 }
665 }
666 else
667 {
668 controls = new ArrayList<LDAPControl>(0);
669 }
670
671
672 return new LDAPMessage(messageID, protocolOp, controls);
673 }
674
675
676
677 /**
678 * Retrieves the name of the protocol associated with this protocol element.
679 *
680 * @return The name of the protocol associated with this protocol element.
681 */
682 public String getProtocolElementName()
683 {
684 return "LDAP";
685 }
686
687
688
689 /**
690 * Retrieves a string representation of this LDAP message.
691 *
692 * @return A string representation of this LDAP message.
693 */
694 public String toString()
695 {
696 StringBuilder buffer = new StringBuilder();
697 toString(buffer);
698 return buffer.toString();
699 }
700
701
702
703 /**
704 * Appends a string representation of this protocol element to the provided
705 * buffer.
706 *
707 * @param buffer The buffer into which the string representation should be
708 * written.
709 */
710 public void toString(StringBuilder buffer)
711 {
712 buffer.append("LDAPMessage(msgID=");
713 buffer.append(messageID);
714 buffer.append(", protocolOp=");
715 if (protocolOp != null) {
716 protocolOp.toString(buffer);
717 } else {
718 buffer.append("null");
719 }
720
721 if (controls != null && !controls.isEmpty())
722 {
723 buffer.append(", controls={ ");
724
725 Iterator<LDAPControl> iterator = controls.iterator();
726 iterator.next().toString(buffer);
727
728 while (iterator.hasNext())
729 {
730 buffer.append(", ");
731 iterator.next().toString(buffer);
732 }
733
734 buffer.append(" }");
735 }
736
737 buffer.append(")");
738 }
739
740
741
742 /**
743 * Appends a string representation of this protocol element to the provided
744 * buffer.
745 *
746 * @param buffer The buffer into which the string representation should be
747 * written.
748 * @param indent The number of spaces that should be used to indent the
749 * resulting string representation.
750 */
751 public void toString(StringBuilder buffer, int indent)
752 {
753 StringBuilder indentBuf = new StringBuilder(indent);
754 for (int i=0 ; i < indent; i++)
755 {
756 indentBuf.append(' ');
757 }
758
759 buffer.append(indentBuf);
760 buffer.append("LDAP Message");
761 buffer.append(EOL);
762
763 buffer.append(indentBuf);
764 buffer.append(" Message ID: ");
765 buffer.append(messageID);
766 buffer.append(EOL);
767
768 buffer.append(indentBuf);
769 buffer.append(" Protocol Op:");
770 buffer.append(EOL);
771 protocolOp.toString(buffer, indent+4);
772
773 if (! controls.isEmpty())
774 {
775 buffer.append(indentBuf);
776 buffer.append(" Controls:");
777
778 for (LDAPControl c : controls)
779 {
780 c.toString(buffer, indent+4);
781 }
782 }
783 }
784 }
785