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    }