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