001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.codec;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025
026 import java.util.ArrayList;
027 import java.util.List;
028
029 import org.apache.directory.shared.asn1.AbstractAsn1Object;
030 import org.apache.directory.shared.asn1.Asn1Object;
031 import org.apache.directory.shared.asn1.ber.tlv.TLV;
032 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
033 import org.apache.directory.shared.asn1.ber.tlv.Value;
034 import org.apache.directory.shared.asn1.codec.EncoderException;
035 import org.apache.directory.shared.ldap.codec.abandon.AbandonRequestCodec;
036 import org.apache.directory.shared.ldap.codec.add.AddRequestCodec;
037 import org.apache.directory.shared.ldap.codec.add.AddResponseCodec;
038 import org.apache.directory.shared.ldap.codec.bind.BindRequestCodec;
039 import org.apache.directory.shared.ldap.codec.bind.BindResponseCodec;
040 import org.apache.directory.shared.ldap.codec.compare.CompareRequestCodec;
041 import org.apache.directory.shared.ldap.codec.compare.CompareResponseCodec;
042 import org.apache.directory.shared.ldap.codec.del.DelRequestCodec;
043 import org.apache.directory.shared.ldap.codec.del.DelResponseCodec;
044 import org.apache.directory.shared.ldap.codec.extended.ExtendedRequestCodec;
045 import org.apache.directory.shared.ldap.codec.extended.ExtendedResponseCodec;
046 import org.apache.directory.shared.ldap.codec.intermediate.IntermediateResponseCodec;
047 import org.apache.directory.shared.ldap.codec.modify.ModifyRequestCodec;
048 import org.apache.directory.shared.ldap.codec.modify.ModifyResponseCodec;
049 import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNRequestCodec;
050 import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNResponseCodec;
051 import org.apache.directory.shared.ldap.codec.search.SearchRequestCodec;
052 import org.apache.directory.shared.ldap.codec.search.SearchResultDoneCodec;
053 import org.apache.directory.shared.ldap.codec.search.SearchResultEntryCodec;
054 import org.apache.directory.shared.ldap.codec.search.SearchResultReferenceCodec;
055 import org.apache.directory.shared.ldap.codec.unbind.UnBindRequestCodec;
056
057
058 /**
059 * The main ldapObject : every Ldap Message are encapsulated in it. It contains
060 * a message Id, a operation (protocolOp) and one ore more Controls.
061 *
062 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
063 * @version $Rev: 806991 $, $Date: 2009-08-23 18:44:02 +0200 (Dim, 23 aoĆ» 2009) $,
064 */
065 public class LdapMessageCodec extends AbstractAsn1Object
066 {
067 // ~ Instance fields
068 // ----------------------------------------------------------------------------
069
070 /** The message ID */
071 private int messageId;
072
073 /** The request or response being carried by the message */
074 private Asn1Object protocolOp;
075
076 /** The controls */
077 private List<ControlCodec> controls;
078
079 /** The current control */
080 private ControlCodec currentControl;
081
082 /** The LdapMessage length */
083 private int ldapMessageLength;
084
085 /** The controls length */
086 private int controlsLength;
087
088 /** The controls sequence length */
089 private int controlsSequenceLength;
090
091
092 // ~ Constructors
093 // -------------------------------------------------------------------------------
094
095 /**
096 * Creates a new LdapMessage object.
097 */
098 public LdapMessageCodec()
099 {
100 super();
101 // We should not create this kind of object directly
102 }
103
104
105 // ~ Methods
106 // ------------------------------------------------------------------------------------
107
108 /**
109 * Get the Control Object at a specific index
110 *
111 * @param i The index of the Control Object to get
112 * @return The selected Control Object
113 */
114 public ControlCodec getControls( int i )
115 {
116 if ( controls != null )
117 {
118 return controls.get( i );
119 }
120 else
121 {
122 return null;
123 }
124 }
125
126
127 /**
128 * Get the Control Objects
129 *
130 * @return The Control Objects
131 */
132 public List<ControlCodec> getControls()
133 {
134 return controls;
135 }
136
137
138 /**
139 * Get the current Control Object
140 *
141 * @return The current Control Object
142 */
143 public ControlCodec getCurrentControl()
144 {
145 return currentControl;
146 }
147
148
149 /**
150 * Add a control to the Controls array
151 *
152 * @param control The Control to add
153 */
154 public void addControl( ControlCodec control )
155 {
156 currentControl = control;
157
158 if ( controls == null )
159 {
160 controls = new ArrayList<ControlCodec>();
161 }
162
163 controls.add( control );
164 }
165
166
167 /**
168 * Set or add a list of controls to the Controls array. If the existing
169 * control array is not null then the given controls will be added
170 *
171 * @param controls The list of Controls to set or add
172 */
173 public void addControls( List<ControlCodec> controls )
174 {
175 if( this.controls == null )
176 {
177 this.controls = controls;
178 }
179 else if( controls != null )
180 {
181 this.controls.addAll( controls );
182 }
183 }
184
185
186 /**
187 * Init the controls array
188 */
189 public void initControls()
190 {
191 controls = new ArrayList<ControlCodec>();
192 }
193
194
195 /**
196 * Get the message ID
197 *
198 * @return The message ID
199 */
200 public int getMessageId()
201 {
202 return messageId;
203 }
204
205
206 /**
207 * Set the message ID
208 *
209 * @param messageId The message ID
210 */
211 public void setMessageId( int messageId )
212 {
213 this.messageId = messageId;
214 }
215
216
217 /**
218 * Get the message type
219 *
220 * @return The message type
221 */
222 public int getMessageType()
223 {
224 return ( ( LdapMessageCodec ) protocolOp ).getMessageType();
225 }
226
227
228 /**
229 * Get the message type Name
230 *
231 * @return The message type name
232 */
233 public String getMessageTypeName()
234 {
235 switch ( ( ( LdapMessageCodec ) protocolOp ).getMessageType() )
236 {
237 case LdapConstants.ABANDON_REQUEST:
238 return "ABANDON_REQUEST";
239
240 case LdapConstants.ADD_REQUEST:
241 return "ADD_REQUEST";
242
243 case LdapConstants.ADD_RESPONSE:
244 return "ADD_RESPONSE";
245
246 case LdapConstants.BIND_REQUEST:
247 return "BIND_REQUEST";
248
249 case LdapConstants.BIND_RESPONSE:
250 return "BIND_RESPONSE";
251
252 case LdapConstants.COMPARE_REQUEST:
253 return "COMPARE_REQUEST";
254
255 case LdapConstants.COMPARE_RESPONSE:
256 return "COMPARE_RESPONSE";
257
258 case LdapConstants.DEL_REQUEST:
259 return "DEL_REQUEST";
260
261 case LdapConstants.DEL_RESPONSE:
262 return "DEL_RESPONSE";
263
264 case LdapConstants.EXTENDED_REQUEST:
265 return "EXTENDED_REQUEST";
266
267 case LdapConstants.EXTENDED_RESPONSE:
268 return "EXTENDED_RESPONSE";
269
270 case LdapConstants.INTERMEDIATE_RESPONSE:
271 return "INTERMEDIATE_RESPONSE";
272
273 case LdapConstants.MODIFYDN_REQUEST:
274 return "MODIFYDN_REQUEST";
275
276 case LdapConstants.MODIFYDN_RESPONSE:
277 return "MODIFYDN_RESPONSE";
278
279 case LdapConstants.MODIFY_REQUEST:
280 return "MODIFY_REQUEST";
281
282 case LdapConstants.MODIFY_RESPONSE:
283 return "MODIFY_RESPONSE";
284
285 case LdapConstants.SEARCH_REQUEST:
286 return "SEARCH_REQUEST";
287
288 case LdapConstants.SEARCH_RESULT_DONE:
289 return "SEARCH_RESULT_DONE";
290
291 case LdapConstants.SEARCH_RESULT_ENTRY:
292 return "SEARCH_RESULT_ENTRY";
293
294 case LdapConstants.SEARCH_RESULT_REFERENCE:
295 return "SEARCH_RESULT_REFERENCE";
296
297 case LdapConstants.UNBIND_REQUEST:
298 return "UNBIND_REQUEST";
299
300 default:
301 return "UNKNOWN";
302 }
303 }
304
305
306 /**
307 * Get the encapsulated Ldap response.
308 *
309 * @return Returns the Ldap response.
310 */
311 public LdapResponseCodec getLdapResponse()
312 {
313 return ( LdapResponseCodec ) protocolOp;
314 }
315
316
317 /**
318 * Get a AbandonRequest ldapObject, assuming that the caller knows that it
319 * is the LdapMessage exact type.
320 *
321 * @return Returns the AbandonRequest ldapObject.
322 */
323 public AbandonRequestCodec getAbandonRequest()
324 {
325 return ( AbandonRequestCodec ) protocolOp;
326 }
327
328
329 /**
330 * Get a AddRequest ldapObject, assuming that the caller knows that it is
331 * the LdapMessage exact type.
332 *
333 * @return Returns the AddRequest ldapObject.
334 */
335 public AddRequestCodec getAddRequest()
336 {
337 return ( AddRequestCodec ) protocolOp;
338 }
339
340
341 /**
342 * Get a AddResponse ldapObject, assuming that the caller knows that it is
343 * the LdapMessage exact type.
344 *
345 * @return Returns the AddResponse ldapObject.
346 */
347 public AddResponseCodec getAddResponse()
348 {
349 return ( AddResponseCodec ) protocolOp;
350 }
351
352
353 /**
354 * Get a BindRequest ldapObject, assuming that the caller knows that it is
355 * the LdapMessage exact type.
356 *
357 * @return Returns the BindRequest ldapObject.
358 */
359 public BindRequestCodec getBindRequest()
360 {
361 return ( BindRequestCodec ) protocolOp;
362 }
363
364
365 /**
366 * Get a BindResponse ldapObject, assuming that the caller knows that it is
367 * the LdapMessage exact type.
368 *
369 * @return Returns the BindResponse ldapObject.
370 */
371 public BindResponseCodec getBindResponse()
372 {
373 return ( BindResponseCodec ) protocolOp;
374 }
375
376
377 /**
378 * Get a CompareRequest ldapObject, assuming that the caller knows that it
379 * is the LdapMessage exact type.
380 *
381 * @return Returns the CompareRequest ldapObject.
382 */
383 public CompareRequestCodec getCompareRequest()
384 {
385 return ( CompareRequestCodec ) protocolOp;
386 }
387
388
389 /**
390 * Get a CompareResponse ldapObject, assuming that the caller knows that it
391 * is the LdapMessage exact type.
392 *
393 * @return Returns the CompareResponse ldapObject.
394 */
395 public CompareResponseCodec getCompareResponse()
396 {
397 return ( CompareResponseCodec ) protocolOp;
398 }
399
400
401 /**
402 * Get a DelRequest ldapObject, assuming that the caller knows that it is
403 * the LdapMessage exact type.
404 *
405 * @return Returns the DelRequest ldapObject.
406 */
407 public DelRequestCodec getDelRequest()
408 {
409 return ( DelRequestCodec ) protocolOp;
410 }
411
412
413 /**
414 * Get a DelResponse ldapObject, assuming that the caller knows that it is
415 * the LdapMessage exact type.
416 *
417 * @return Returns the DelResponse ldapObject.
418 */
419 public DelResponseCodec getDelResponse()
420 {
421 return ( DelResponseCodec ) protocolOp;
422 }
423
424
425 /**
426 * Get a ExtendedRequest ldapObject, assuming that the caller knows that it
427 * is the LdapMessage exact type.
428 *
429 * @return Returns the ExtendedRequest ldapObject.
430 */
431 public ExtendedRequestCodec getExtendedRequest()
432 {
433 return ( ExtendedRequestCodec ) protocolOp;
434 }
435
436
437 /**
438 * Get a ExtendedResponse ldapObject, assuming that the caller knows that it
439 * is the LdapMessage exact type.
440 *
441 * @return Returns the ExtendedResponse ldapObject.
442 */
443 public ExtendedResponseCodec getExtendedResponse()
444 {
445 return ( ExtendedResponseCodec ) protocolOp;
446 }
447
448
449 /**
450 * Get a IntermediateResponse ldapObject, assuming that the caller knows that it
451 * is the LdapMessage exact type.
452 *
453 * @return Returns the IntermediateResponse ldapObject.
454 */
455 public IntermediateResponseCodec getIntermediateResponse()
456 {
457 return ( IntermediateResponseCodec ) protocolOp;
458 }
459
460
461 /**
462 * Get a ModifyDNRequest ldapObject, assuming that the caller knows that it
463 * is the LdapMessage exact type.
464 *
465 * @return Returns the ModifyDNRequest ldapObject.
466 */
467 public ModifyDNRequestCodec getModifyDNRequest()
468 {
469 return ( ModifyDNRequestCodec ) protocolOp;
470 }
471
472
473 /**
474 * Get a ModifyDNResponse ldapObject, assuming that the caller knows that it
475 * is the LdapMessage exact type.
476 *
477 * @return Returns the ModifyDNResponse ldapObject.
478 */
479 public ModifyDNResponseCodec getModifyDNResponse()
480 {
481 return ( ModifyDNResponseCodec ) protocolOp;
482 }
483
484
485 /**
486 * Get a ModifyRequest ldapObject, assuming that the caller knows that it is
487 * the LdapMessage exact type.
488 *
489 * @return Returns the ModifyRequest ldapObject.
490 */
491 public ModifyRequestCodec getModifyRequest()
492 {
493 return ( ModifyRequestCodec ) protocolOp;
494 }
495
496
497 /**
498 * Get a ModifyResponse ldapObject, assuming that the caller knows that it
499 * is the LdapMessage exact type.
500 *
501 * @return Returns the ModifyResponse ldapObject.
502 */
503 public ModifyResponseCodec getModifyResponse()
504 {
505 return ( ModifyResponseCodec ) protocolOp;
506 }
507
508
509 /**
510 * Get a SearchRequest ldapObject, assuming that the caller knows that it is
511 * the LdapMessage exact type.
512 *
513 * @return Returns the SearchRequest ldapObject.
514 */
515 public SearchRequestCodec getSearchRequest()
516 {
517 return ( SearchRequestCodec ) protocolOp;
518 }
519
520
521 /**
522 * Get a SearchResultDone ldapObject, assuming that the caller knows that it
523 * is the LdapMessage exact type.
524 *
525 * @return Returns the SearchRequestDone ldapObject.
526 */
527 public SearchResultDoneCodec getSearchResultDone()
528 {
529 return ( SearchResultDoneCodec ) protocolOp;
530 }
531
532
533 /**
534 * Get a SearchResultEntry ldapObject, assuming that the caller knows that
535 * it is the LdapMessage exact type.
536 *
537 * @return Returns the SearchResultEntry ldapObject.
538 */
539 public SearchResultEntryCodec getSearchResultEntry()
540 {
541 return ( SearchResultEntryCodec ) protocolOp;
542 }
543
544
545 /**
546 * Get a SearchResultReference ldapObject, assuming that the caller knows
547 * that it is the LdapMessage exact type.
548 *
549 * @return Returns the SearchResultReference ldapObject.
550 */
551 public SearchResultReferenceCodec getSearchResultReference()
552 {
553 return ( SearchResultReferenceCodec ) protocolOp;
554 }
555
556
557 /**
558 * Get a UnBindRequest ldapObject, assuming that the caller knows that it is
559 * the LdapMessage exact type.
560 *
561 * @return Returns the UnBindRequest ldapObject.
562 */
563 public UnBindRequestCodec getUnBindRequest()
564 {
565 return ( UnBindRequestCodec ) protocolOp;
566 }
567
568
569 /**
570 * Set the ProtocolOP
571 *
572 * @param protocolOp The protocolOp to set.
573 */
574 public void setProtocolOP( Asn1Object protocolOp )
575 {
576 this.protocolOp = protocolOp;
577 }
578
579
580 /**
581 * Compute the LdapMessage length LdapMessage :
582 * 0x30 L1
583 * |
584 * +--> 0x02 0x0(1-4) [0..2^31-1] (MessageId)
585 * +--> protocolOp
586 * [+--> Controls]
587 *
588 * MessageId length = Length(0x02) + length(MessageId) + MessageId.length
589 * L1 = length(ProtocolOp)
590 * LdapMessage length = Length(0x30) + Length(L1) + MessageId length + L1
591 */
592 public int computeLength()
593 {
594 // The length of the MessageId. It's the sum of
595 // - the tag (0x02), 1 byte
596 // - the length of the Id length, 1 byte
597 // - the Id length, 1 to 4 bytes
598 ldapMessageLength = 1 + 1 + Value.getNbBytes( messageId );
599
600 // Get the protocolOp length
601 int protocolOpLength = protocolOp.computeLength();
602
603 // Add the protocol length to the message length
604 ldapMessageLength += protocolOpLength;
605
606 // Do the same thing for Controls, if any.
607 if ( controls != null )
608 {
609 // Controls :
610 // 0xA0 L3
611 // |
612 // +--> 0x30 L4
613 // +--> 0x30 L5
614 // +--> ...
615 // +--> 0x30 Li
616 // +--> ...
617 // +--> 0x30 Ln
618 //
619 // L3 = Length(0x30) + Length(L5) + L5
620 // + Length(0x30) + Length(L6) + L6
621 // + ...
622 // + Length(0x30) + Length(Li) + Li
623 // + ...
624 // + Length(0x30) + Length(Ln) + Ln
625 //
626 // LdapMessageLength = LdapMessageLength + Length(0x90)
627 // + Length(L3) + L3
628 controlsSequenceLength = 0;
629
630 // We may have more than one control. ControlsLength is L4.
631 for ( ControlCodec control:controls )
632 {
633 controlsSequenceLength += control.computeLength();
634 }
635
636 // Computes the controls length
637 controlsLength = controlsSequenceLength; // 1 + Length.getNbBytes(
638 // controlsSequenceLength
639 // ) + controlsSequenceLength;
640
641 // Now, add the tag and the length of the controls length
642 ldapMessageLength += 1 + TLV.getNbBytes( controlsSequenceLength ) + controlsSequenceLength;
643 }
644
645 // finally, calculate the global message size :
646 // length(Tag) + Length(length) + length
647
648 return 1 + ldapMessageLength + TLV.getNbBytes( ldapMessageLength );
649 }
650
651
652 /**
653 * Generate the PDU which contains the encoded object.
654 *
655 * The generation is done in two phases :
656 * - first, we compute the length of each part and the
657 * global PDU length
658 * - second, we produce the PDU.
659 *
660 * 0x30 L1
661 * |
662 * +--> 0x02 L2 MessageId
663 * +--> ProtocolOp
664 * +--> Controls
665 *
666 * L2 = Length(MessageId)
667 * L1 = Length(0x02) + Length(L2) + L2 + Length(ProtocolOp) + Length(Controls)
668 * LdapMessageLength = Length(0x30) + Length(L1) + L1
669 *
670 * @param buffer The encoded PDU
671 * @return A ByteBuffer that contaons the PDU
672 * @throws EncoderException If anything goes wrong.
673 */
674 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
675 {
676 // Allocate the bytes buffer.
677 ByteBuffer bb = ByteBuffer.allocate( computeLength() );
678
679 try
680 {
681 // The LdapMessage Sequence
682 bb.put( UniversalTag.SEQUENCE_TAG );
683
684 // The length has been calculated by the computeLength method
685 bb.put( TLV.getBytes( ldapMessageLength ) );
686 }
687 catch ( BufferOverflowException boe )
688 {
689 throw new EncoderException( "The PDU buffer size is too small !" );
690 }
691
692 // The message Id
693 Value.encode( bb, messageId );
694
695 // Add the protocolOp part
696 protocolOp.encode( bb );
697
698 // Do the same thing for Controls, if any.
699 if ( controls != null )
700 {
701 // Encode the controls
702 bb.put( ( byte ) LdapConstants.CONTROLS_TAG );
703 bb.put( TLV.getBytes( controlsLength ) );
704
705 // Encode each control
706 for ( ControlCodec control:controls )
707 {
708 control.encode( bb );
709 }
710 }
711
712 return bb;
713 }
714
715
716 /**
717 * Get a String representation of a LdapMessage
718 *
719 * @return A LdapMessage String
720 */
721 public String toString()
722 {
723 StringBuffer sb = new StringBuffer();
724
725 sb.append( "LdapMessage\n" );
726 sb.append( " message Id : " ).append( messageId ).append( '\n' );
727 sb.append( protocolOp );
728
729 if ( controls != null )
730 {
731 for ( ControlCodec control:controls )
732 {
733 sb.append( control );
734 }
735 }
736
737 return sb.toString();
738 }
739 }