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: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 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 * Init the controls array
169 */
170 public void initControls()
171 {
172 controls = new ArrayList<ControlCodec>();
173 }
174
175
176 /**
177 * Get the message ID
178 *
179 * @return The message ID
180 */
181 public int getMessageId()
182 {
183 return messageId;
184 }
185
186
187 /**
188 * Set the message ID
189 *
190 * @param messageId The message ID
191 */
192 public void setMessageId( int messageId )
193 {
194 this.messageId = messageId;
195 }
196
197
198 /**
199 * Get the message type
200 *
201 * @return The message type
202 */
203 public int getMessageType()
204 {
205 return ( ( LdapMessageCodec ) protocolOp ).getMessageType();
206 }
207
208
209 /**
210 * Get the message type Name
211 *
212 * @return The message type name
213 */
214 public String getMessageTypeName()
215 {
216 switch ( ( ( LdapMessageCodec ) protocolOp ).getMessageType() )
217 {
218 case LdapConstants.ABANDON_REQUEST:
219 return "ABANDON_REQUEST";
220
221 case LdapConstants.ADD_REQUEST:
222 return "ADD_REQUEST";
223
224 case LdapConstants.ADD_RESPONSE:
225 return "ADD_RESPONSE";
226
227 case LdapConstants.BIND_REQUEST:
228 return "BIND_REQUEST";
229
230 case LdapConstants.BIND_RESPONSE:
231 return "BIND_RESPONSE";
232
233 case LdapConstants.COMPARE_REQUEST:
234 return "COMPARE_REQUEST";
235
236 case LdapConstants.COMPARE_RESPONSE:
237 return "COMPARE_RESPONSE";
238
239 case LdapConstants.DEL_REQUEST:
240 return "DEL_REQUEST";
241
242 case LdapConstants.DEL_RESPONSE:
243 return "DEL_RESPONSE";
244
245 case LdapConstants.EXTENDED_REQUEST:
246 return "EXTENDED_REQUEST";
247
248 case LdapConstants.EXTENDED_RESPONSE:
249 return "EXTENDED_RESPONSE";
250
251 case LdapConstants.INTERMEDIATE_RESPONSE:
252 return "INTERMEDIATE_RESPONSE";
253
254 case LdapConstants.MODIFYDN_REQUEST:
255 return "MODIFYDN_REQUEST";
256
257 case LdapConstants.MODIFYDN_RESPONSE:
258 return "MODIFYDN_RESPONSE";
259
260 case LdapConstants.MODIFY_REQUEST:
261 return "MODIFY_REQUEST";
262
263 case LdapConstants.MODIFY_RESPONSE:
264 return "MODIFY_RESPONSE";
265
266 case LdapConstants.SEARCH_REQUEST:
267 return "SEARCH_REQUEST";
268
269 case LdapConstants.SEARCH_RESULT_DONE:
270 return "SEARCH_RESULT_DONE";
271
272 case LdapConstants.SEARCH_RESULT_ENTRY:
273 return "SEARCH_RESULT_ENTRY";
274
275 case LdapConstants.SEARCH_RESULT_REFERENCE:
276 return "SEARCH_RESULT_REFERENCE";
277
278 case LdapConstants.UNBIND_REQUEST:
279 return "UNBIND_REQUEST";
280
281 default:
282 return "UNKNOWN";
283 }
284 }
285
286
287 /**
288 * Get the encapsulated Ldap response.
289 *
290 * @return Returns the Ldap response.
291 */
292 public LdapResponseCodec getLdapResponse()
293 {
294 return ( LdapResponseCodec ) protocolOp;
295 }
296
297
298 /**
299 * Get a AbandonRequest ldapObject, assuming that the caller knows that it
300 * is the LdapMessage exact type.
301 *
302 * @return Returns the AbandonRequest ldapObject.
303 */
304 public AbandonRequestCodec getAbandonRequest()
305 {
306 return ( AbandonRequestCodec ) protocolOp;
307 }
308
309
310 /**
311 * Get a AddRequest ldapObject, assuming that the caller knows that it is
312 * the LdapMessage exact type.
313 *
314 * @return Returns the AddRequest ldapObject.
315 */
316 public AddRequestCodec getAddRequest()
317 {
318 return ( AddRequestCodec ) protocolOp;
319 }
320
321
322 /**
323 * Get a AddResponse ldapObject, assuming that the caller knows that it is
324 * the LdapMessage exact type.
325 *
326 * @return Returns the AddResponse ldapObject.
327 */
328 public AddResponseCodec getAddResponse()
329 {
330 return ( AddResponseCodec ) protocolOp;
331 }
332
333
334 /**
335 * Get a BindRequest ldapObject, assuming that the caller knows that it is
336 * the LdapMessage exact type.
337 *
338 * @return Returns the BindRequest ldapObject.
339 */
340 public BindRequestCodec getBindRequest()
341 {
342 return ( BindRequestCodec ) protocolOp;
343 }
344
345
346 /**
347 * Get a BindResponse ldapObject, assuming that the caller knows that it is
348 * the LdapMessage exact type.
349 *
350 * @return Returns the BindResponse ldapObject.
351 */
352 public BindResponseCodec getBindResponse()
353 {
354 return ( BindResponseCodec ) protocolOp;
355 }
356
357
358 /**
359 * Get a CompareRequest ldapObject, assuming that the caller knows that it
360 * is the LdapMessage exact type.
361 *
362 * @return Returns the CompareRequest ldapObject.
363 */
364 public CompareRequestCodec getCompareRequest()
365 {
366 return ( CompareRequestCodec ) protocolOp;
367 }
368
369
370 /**
371 * Get a CompareResponse ldapObject, assuming that the caller knows that it
372 * is the LdapMessage exact type.
373 *
374 * @return Returns the CompareResponse ldapObject.
375 */
376 public CompareResponseCodec getCompareResponse()
377 {
378 return ( CompareResponseCodec ) protocolOp;
379 }
380
381
382 /**
383 * Get a DelRequest ldapObject, assuming that the caller knows that it is
384 * the LdapMessage exact type.
385 *
386 * @return Returns the DelRequest ldapObject.
387 */
388 public DelRequestCodec getDelRequest()
389 {
390 return ( DelRequestCodec ) protocolOp;
391 }
392
393
394 /**
395 * Get a DelResponse ldapObject, assuming that the caller knows that it is
396 * the LdapMessage exact type.
397 *
398 * @return Returns the DelResponse ldapObject.
399 */
400 public DelResponseCodec getDelResponse()
401 {
402 return ( DelResponseCodec ) protocolOp;
403 }
404
405
406 /**
407 * Get a ExtendedRequest ldapObject, assuming that the caller knows that it
408 * is the LdapMessage exact type.
409 *
410 * @return Returns the ExtendedRequest ldapObject.
411 */
412 public ExtendedRequestCodec getExtendedRequest()
413 {
414 return ( ExtendedRequestCodec ) protocolOp;
415 }
416
417
418 /**
419 * Get a ExtendedResponse ldapObject, assuming that the caller knows that it
420 * is the LdapMessage exact type.
421 *
422 * @return Returns the ExtendedResponse ldapObject.
423 */
424 public ExtendedResponseCodec getExtendedResponse()
425 {
426 return ( ExtendedResponseCodec ) protocolOp;
427 }
428
429
430 /**
431 * Get a IntermediateResponse ldapObject, assuming that the caller knows that it
432 * is the LdapMessage exact type.
433 *
434 * @return Returns the IntermediateResponse ldapObject.
435 */
436 public IntermediateResponseCodec getIntermediateResponse()
437 {
438 return ( IntermediateResponseCodec ) protocolOp;
439 }
440
441
442 /**
443 * Get a ModifyDNRequest ldapObject, assuming that the caller knows that it
444 * is the LdapMessage exact type.
445 *
446 * @return Returns the ModifyDNRequest ldapObject.
447 */
448 public ModifyDNRequestCodec getModifyDNRequest()
449 {
450 return ( ModifyDNRequestCodec ) protocolOp;
451 }
452
453
454 /**
455 * Get a ModifyDNResponse ldapObject, assuming that the caller knows that it
456 * is the LdapMessage exact type.
457 *
458 * @return Returns the ModifyDNResponse ldapObject.
459 */
460 public ModifyDNResponseCodec getModifyDNResponse()
461 {
462 return ( ModifyDNResponseCodec ) protocolOp;
463 }
464
465
466 /**
467 * Get a ModifyRequest ldapObject, assuming that the caller knows that it is
468 * the LdapMessage exact type.
469 *
470 * @return Returns the ModifyRequest ldapObject.
471 */
472 public ModifyRequestCodec getModifyRequest()
473 {
474 return ( ModifyRequestCodec ) protocolOp;
475 }
476
477
478 /**
479 * Get a ModifyResponse ldapObject, assuming that the caller knows that it
480 * is the LdapMessage exact type.
481 *
482 * @return Returns the ModifyResponse ldapObject.
483 */
484 public ModifyResponseCodec getModifyResponse()
485 {
486 return ( ModifyResponseCodec ) protocolOp;
487 }
488
489
490 /**
491 * Get a SearchRequest ldapObject, assuming that the caller knows that it is
492 * the LdapMessage exact type.
493 *
494 * @return Returns the SearchRequest ldapObject.
495 */
496 public SearchRequestCodec getSearchRequest()
497 {
498 return ( SearchRequestCodec ) protocolOp;
499 }
500
501
502 /**
503 * Get a SearchResultDone ldapObject, assuming that the caller knows that it
504 * is the LdapMessage exact type.
505 *
506 * @return Returns the SearchRequestDone ldapObject.
507 */
508 public SearchResultDoneCodec getSearchResultDone()
509 {
510 return ( SearchResultDoneCodec ) protocolOp;
511 }
512
513
514 /**
515 * Get a SearchResultEntry ldapObject, assuming that the caller knows that
516 * it is the LdapMessage exact type.
517 *
518 * @return Returns the SearchResultEntry ldapObject.
519 */
520 public SearchResultEntryCodec getSearchResultEntry()
521 {
522 return ( SearchResultEntryCodec ) protocolOp;
523 }
524
525
526 /**
527 * Get a SearchResultReference ldapObject, assuming that the caller knows
528 * that it is the LdapMessage exact type.
529 *
530 * @return Returns the SearchResultReference ldapObject.
531 */
532 public SearchResultReferenceCodec getSearchResultReference()
533 {
534 return ( SearchResultReferenceCodec ) protocolOp;
535 }
536
537
538 /**
539 * Get a UnBindRequest ldapObject, assuming that the caller knows that it is
540 * the LdapMessage exact type.
541 *
542 * @return Returns the UnBindRequest ldapObject.
543 */
544 public UnBindRequestCodec getUnBindRequest()
545 {
546 return ( UnBindRequestCodec ) protocolOp;
547 }
548
549
550 /**
551 * Set the ProtocolOP
552 *
553 * @param protocolOp The protocolOp to set.
554 */
555 public void setProtocolOP( Asn1Object protocolOp )
556 {
557 this.protocolOp = protocolOp;
558 }
559
560
561 /**
562 * Compute the LdapMessage length LdapMessage :
563 * 0x30 L1
564 * |
565 * +--> 0x02 0x0(1-4) [0..2^31-1] (MessageId)
566 * +--> protocolOp
567 * [+--> Controls]
568 *
569 * MessageId length = Length(0x02) + length(MessageId) + MessageId.length
570 * L1 = length(ProtocolOp)
571 * LdapMessage length = Length(0x30) + Length(L1) + MessageId length + L1
572 */
573 public int computeLength()
574 {
575 // The length of the MessageId. It's the sum of
576 // - the tag (0x02), 1 byte
577 // - the length of the Id length, 1 byte
578 // - the Id length, 1 to 4 bytes
579 ldapMessageLength = 1 + 1 + Value.getNbBytes( messageId );
580
581 // Get the protocolOp length
582 int protocolOpLength = protocolOp.computeLength();
583
584 // Add the protocol length to the message length
585 ldapMessageLength += protocolOpLength;
586
587 // Do the same thing for Controls, if any.
588 if ( controls != null )
589 {
590 // Controls :
591 // 0xA0 L3
592 // |
593 // +--> 0x30 L4
594 // +--> 0x30 L5
595 // +--> ...
596 // +--> 0x30 Li
597 // +--> ...
598 // +--> 0x30 Ln
599 //
600 // L3 = Length(0x30) + Length(L5) + L5
601 // + Length(0x30) + Length(L6) + L6
602 // + ...
603 // + Length(0x30) + Length(Li) + Li
604 // + ...
605 // + Length(0x30) + Length(Ln) + Ln
606 //
607 // LdapMessageLength = LdapMessageLength + Length(0x90)
608 // + Length(L3) + L3
609 controlsSequenceLength = 0;
610
611 // We may have more than one control. ControlsLength is L4.
612 for ( ControlCodec control:controls )
613 {
614 controlsSequenceLength += control.computeLength();
615 }
616
617 // Computes the controls length
618 controlsLength = controlsSequenceLength; // 1 + Length.getNbBytes(
619 // controlsSequenceLength
620 // ) + controlsSequenceLength;
621
622 // Now, add the tag and the length of the controls length
623 ldapMessageLength += 1 + TLV.getNbBytes( controlsSequenceLength ) + controlsSequenceLength;
624 }
625
626 // finally, calculate the global message size :
627 // length(Tag) + Length(length) + length
628
629 return 1 + ldapMessageLength + TLV.getNbBytes( ldapMessageLength );
630 }
631
632
633 /**
634 * Generate the PDU which contains the encoded object.
635 *
636 * The generation is done in two phases :
637 * - first, we compute the length of each part and the
638 * global PDU length
639 * - second, we produce the PDU.
640 *
641 * 0x30 L1
642 * |
643 * +--> 0x02 L2 MessageId
644 * +--> ProtocolOp
645 * +--> Controls
646 *
647 * L2 = Length(MessageId)
648 * L1 = Length(0x02) + Length(L2) + L2 + Length(ProtocolOp) + Length(Controls)
649 * LdapMessageLength = Length(0x30) + Length(L1) + L1
650 *
651 * @param buffer The encoded PDU
652 * @return A ByteBuffer that contaons the PDU
653 * @throws EncoderException If anything goes wrong.
654 */
655 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
656 {
657 // Allocate the bytes buffer.
658 ByteBuffer bb = ByteBuffer.allocate( computeLength() );
659
660 try
661 {
662 // The LdapMessage Sequence
663 bb.put( UniversalTag.SEQUENCE_TAG );
664
665 // The length has been calculated by the computeLength method
666 bb.put( TLV.getBytes( ldapMessageLength ) );
667 }
668 catch ( BufferOverflowException boe )
669 {
670 throw new EncoderException( "The PDU buffer size is too small !" );
671 }
672
673 // The message Id
674 Value.encode( bb, messageId );
675
676 // Add the protocolOp part
677 protocolOp.encode( bb );
678
679 // Do the same thing for Controls, if any.
680 if ( controls != null )
681 {
682 // Encode the controls
683 bb.put( ( byte ) LdapConstants.CONTROLS_TAG );
684 bb.put( TLV.getBytes( controlsLength ) );
685
686 // Encode each control
687 for ( ControlCodec control:controls )
688 {
689 control.encode( bb );
690 }
691 }
692
693 return bb;
694 }
695
696
697 /**
698 * Get a String representation of a LdapMessage
699 *
700 * @return A LdapMessage String
701 */
702 public String toString()
703 {
704 StringBuffer sb = new StringBuffer();
705
706 sb.append( "LdapMessage\n" );
707 sb.append( " message Id : " ).append( messageId ).append( '\n' );
708 sb.append( protocolOp );
709
710 if ( controls != null )
711 {
712 for ( ControlCodec control:controls )
713 {
714 sb.append( control );
715 }
716 }
717
718 return sb.toString();
719 }
720 }