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.server.kerberos.shared.messages.value;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.server.kerberos.shared.messages.value.types.TransitedEncodingType;
027    import org.apache.directory.shared.asn1.AbstractAsn1Object;
028    import org.apache.directory.shared.asn1.ber.tlv.TLV;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.EncoderException;
032    import org.apache.directory.shared.ldap.util.StringTools;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    
037    /**
038     * The TransitedEncoding structure.
039     * 
040     * The ASN.1 grammar is :
041     * 
042     * -- encoded Transited field
043     * TransitedEncoding       ::= SEQUENCE {
044     *         tr-type         [0] Int32 -- must be registered --,
045     *         contents        [1] OCTET STRING
046     * }
047     * 
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev: 642496 $, $Date: 2008-03-29 05:09:22 +0200 (Sat, 29 Mar 2008) $
050     */
051    public class TransitedEncoding extends AbstractAsn1Object
052    {
053        /** The logger */
054        private static final Logger log = LoggerFactory.getLogger( TransitedEncoding.class );
055    
056        /** Speedup for logs */
057        private static final boolean IS_DEBUG = log.isDebugEnabled();
058    
059        /** The transited type. One of :
060         * NULL
061         * DOMAIN_X500_COMPRESS
062         */
063        private TransitedEncodingType trType;
064    
065        /** The transited data */
066        private byte[] contents;
067    
068        // Storage for computed lengths
069        private transient int trTypeLength;
070        private transient int contentsLength;
071        private transient int transitedEncodingLength;
072    
073    
074        /**
075         * Creates a new instance of TransitedEncoding.
076         */
077        public TransitedEncoding()
078        {
079            trType = TransitedEncodingType.NULL;
080            contents = new byte[0];
081        }
082    
083    
084        /**
085         * Creates a new instance of TransitedEncoding.
086         *
087         * @param trType
088         * @param contents
089         */
090        public TransitedEncoding( TransitedEncodingType trType, byte[] contents )
091        {
092            this.trType = trType;
093            this.contents = contents;
094        }
095    
096    
097        /**
098         * Returns the contents.
099         *
100         * @return The contents.
101         */
102        public byte[] getContents()
103        {
104            return contents;
105        }
106        
107        
108        /**
109         * Set the contents
110         * @param contents The contents
111         */
112        public void setContents( byte[] contents )
113        {
114            this.contents = contents;
115        }
116    
117    
118        /**
119         * Returns the {@link TransitedEncodingType}.
120         *
121         * @return The {@link TransitedEncodingType}.
122         */
123        public TransitedEncodingType getTrType()
124        {
125            return trType;
126        }
127        
128        
129        /**
130         * Set the transited encoding type
131         * @param trType The transited encoding type
132         */
133        public void setTrType( TransitedEncodingType trType )
134        {
135            this.trType = trType;
136        }
137    
138    
139        /**
140         * Compute the TransitedEncoding length
141         * 
142         * TransitedEncoding :
143         * 
144         * 0x30 L1 TransitedEncoding
145         *  |
146         *  +--> 0xA0 L2 trType tag
147         *  |     |
148         *  |     +--> 0x02 L2-1 trType (int)
149         *  |
150         *  +--> 0xA1 L3 contents tag
151         *        |
152         *        +--> 0x04 L3-1 contents (OCTET STRING)
153         *        
154         *  where L1 = L2 + lenght(0xA0) + length(L2) +
155         *             L3 + lenght(0xA1) + length(L3) 
156         *  and
157         *  L2 = L2-1 + length(0x02) + length( L2-1) 
158         *  L3 = L3-1 + length(0x04) + length( L3-1) 
159         */
160        public int computeLength()
161        {
162            // Compute the trType. The Length will always be contained in 1 byte
163            trTypeLength = 1 + 1 + Value.getNbBytes( trType.getOrdinal() );
164            transitedEncodingLength = 1 + TLV.getNbBytes( trTypeLength ) + trTypeLength;
165    
166            // Compute the keyValue
167            if ( contents == null )
168            {
169                contentsLength = 1 + 1;
170            }
171            else
172            {
173                contentsLength = 1 + TLV.getNbBytes( contents.length ) + contents.length;
174            }
175    
176            transitedEncodingLength += 1 + TLV.getNbBytes( contentsLength ) + contentsLength;
177    
178            // Compute the whole sequence length
179            int transitedEncodingSeqLength = 1 + Value.getNbBytes( transitedEncodingLength ) + transitedEncodingLength;
180    
181            return transitedEncodingSeqLength;
182    
183        }
184    
185    
186        /**
187         * Encode the TransitedEncoding message to a PDU. 
188         * 
189         * TransitedEncoding :
190         * 
191         * 0x30 LL
192         *   0xA0 LL 
193         *     0x02 0x01 trType
194         *   0xA1 LL 
195         *     0x04 LL adData
196         * 
197         * @param buffer The buffer where to put the PDU. It should have been allocated
198         * before, with the right size.
199         * @return The constructed PDU.
200         */
201        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
202        {
203            if ( buffer == null )
204            {
205                throw new EncoderException( "Cannot put a PDU in a null buffer !" );
206            }
207    
208            try
209            {
210                // The AuthorizationDataEntry SEQ Tag
211                buffer.put( UniversalTag.SEQUENCE_TAG );
212                buffer.put( TLV.getBytes( transitedEncodingLength ) );
213    
214                // The tr-type, first the tag, then the value
215                buffer.put( ( byte ) 0xA0 );
216                buffer.put( TLV.getBytes( trTypeLength ) );
217                Value.encode( buffer, trType.getOrdinal() );
218    
219                // The contents, first the tag, then the value
220                buffer.put( ( byte ) 0xA1 );
221                buffer.put( TLV.getBytes( contentsLength ) );
222                Value.encode( buffer, contents );
223            }
224            catch ( BufferOverflowException boe )
225            {
226                log.error(
227                    "Cannot encode the TransitedEncoding object, the PDU size is {} when only {} bytes has been allocated",
228                    1 + TLV.getNbBytes( transitedEncodingLength ) + transitedEncodingLength, buffer.capacity() );
229                throw new EncoderException( "The PDU buffer size is too small !" );
230            }
231    
232            if ( IS_DEBUG )
233            {
234                log.debug( "TransitedEncoding encoding : {}", StringTools.dumpBytes( buffer.array() ) );
235                log.debug( "TransitedEncoding initial value : {}", toString() );
236            }
237    
238            return buffer;
239        }
240    
241    
242        /**
243         * @see Object#toString()
244         */
245        public String toString()
246        {
247            StringBuilder sb = new StringBuilder();
248    
249            sb.append( "TransitedEncoding : {\n" );
250            sb.append( "    tr-type: " ).append( trType ).append( '\n' );
251    
252            sb.append( "    contents: " ).append( StringTools.dumpBytes( contents ) ).append( "\n}\n" );
253    
254            return sb.toString();
255        }
256    }