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    }