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    import java.util.ArrayList;
026    import java.util.List;
027    
028    import org.apache.directory.server.kerberos.shared.messages.Encodable;
029    import org.apache.directory.shared.asn1.AbstractAsn1Object;
030    import org.apache.directory.shared.asn1.ber.tlv.TLV;
031    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
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     * An authorization data container.
040     * 
041     * The ASN.1 grammar is :
042     * 
043     * -- NOTE: AuthorizationData is always used as an OPTIONAL field and
044     * -- should not be empty.
045     * AuthorizationData       ::= SEQUENCE OF AuthorizationDataEntry
046     *
047     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
048     * @version $Rev: 587531 $, $Date: 2007-10-23 17:59:10 +0300 (Tue, 23 Oct 2007) $
049     */
050    public class AuthorizationData extends AbstractAsn1Object implements Encodable
051    {
052        /** The logger */
053        private static final Logger log = LoggerFactory.getLogger( AuthorizationData.class );
054    
055        /** Speedup for logs */
056        private static final boolean IS_DEBUG = log.isDebugEnabled();
057    
058        /** The list of AuthrorizationData elements */
059        private List<AuthorizationDataEntry> entries = new ArrayList<AuthorizationDataEntry>();
060    
061        // Storage for computed lengths
062        private transient int authorizationDataLength;
063    
064    
065        /**
066         * Creates a new instance of AuthorizationData.
067         */
068        public AuthorizationData()
069        {
070            // used by ASN.1 decoder
071        }
072    
073    
074        /**
075         * Adds all {@link AuthorizationData} entries to this {@link AuthorizationData}.
076         *
077         * @param data
078         */
079        public void add( AuthorizationData data )
080        {
081            entries.addAll( data.entries );
082        }
083    
084    
085        /**
086         * Adds an {@link AuthorizationDataEntry} to this {@link AuthorizationData}.
087         *
088         * @param entry
089         */
090        public void add( AuthorizationDataEntry entry )
091        {
092            entries.add( entry );
093        }
094    
095    
096        /**
097         * @return The AuthorizationdataEntry list
098         */
099        public List<AuthorizationDataEntry> getEntries()
100        {
101            return entries;
102        }
103    
104    
105        /**
106         * Compute the AuthorizationData length
107         * 
108         * AuthorizationData :
109         * 
110         * 0x30 L1 AuthorizationData
111         *  |
112         *  +--> 0x30 L2 AuthorizationDataEntry
113         *  |
114         *  +--> 0x30 L2 AuthorizationDataEntry
115         *  |
116         *  ...
117         *  |
118         *  +--> 0x30 L2 AuthorizationDataEntry
119         */
120        public int computeLength()
121        {
122            if ( ( entries == null ) || ( entries.size() == 0 ) )
123            {
124                authorizationDataLength = 1;
125    
126                return authorizationDataLength + 1;
127            }
128            else
129            {
130                authorizationDataLength = 0;
131    
132                for ( AuthorizationDataEntry entry : entries )
133                {
134                    authorizationDataLength += entry.computeLength();
135                }
136    
137                return 1 + TLV.getNbBytes( authorizationDataLength ) + authorizationDataLength;
138            }
139        }
140    
141    
142        /**
143         * Encode the AuthorizationData message to a PDU. 
144         * 
145         * AuthorizationData :
146         * 
147         * 0x30 LL
148         *   0x30 LL AuthorizationDataEntry 
149         *   0x30 LL AuthorizationDataEntry
150         *   ... 
151         *   0x30 LL AuthorizationDataEntry 
152         * 
153         * @param buffer The buffer where to put the PDU. It should have been allocated
154         * before, with the right size.
155         * @return The constructed PDU.
156         */
157        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
158        {
159            if ( buffer == null )
160            {
161                throw new EncoderException( "Cannot put a PDU in a null buffer !" );
162            }
163    
164            try
165            {
166                // The AuthorizationData SEQ Tag
167                buffer.put( UniversalTag.SEQUENCE_TAG );
168                buffer.put( TLV.getBytes( authorizationDataLength ) );
169    
170                // Each entry, if any
171                if ( ( entries != null ) && ( entries.size() != 0 ) )
172                {
173                    for ( AuthorizationDataEntry entry : entries )
174                    {
175                        entry.encode( buffer );
176                    }
177                }
178            }
179            catch ( BufferOverflowException boe )
180            {
181                log.error(
182                    "Cannot encode the AuthorizationData object, the PDU size is {} when only {} bytes has been allocated",
183                    1 + TLV.getNbBytes( authorizationDataLength ) + authorizationDataLength, buffer.capacity() );
184                throw new EncoderException( "The PDU buffer size is too small !" );
185            }
186    
187            if ( IS_DEBUG )
188            {
189                log.debug( "AuthorizationData encoding : {}", StringTools.dumpBytes( buffer.array() ) );
190                log.debug( "AuthorizationData initial value : {}", toString() );
191            }
192    
193            return buffer;
194        }
195    
196    
197        /**
198         * @see Object#toString()
199         */
200        public String toString()
201        {
202            return toString( "" );
203        }
204    
205    
206        /**
207         * @see Object#toString()
208         */
209        public String toString( String tabs )
210        {
211            StringBuilder sb = new StringBuilder();
212    
213            if ( ( entries == null ) || ( entries.size() == 0 ) )
214            {
215                sb.append( tabs ).append( "AuthorizationData : {}\n" );
216            }
217            else
218            {
219                sb.append( tabs ).append( "AuthorizationData : {\n" );
220                boolean isFirst = true;
221    
222                for ( AuthorizationDataEntry entry : entries )
223                {
224                    if ( isFirst )
225                    {
226                        isFirst = false;
227                    }
228                    else
229                    {
230                        sb.append( '\n' );
231                    }
232    
233                    sb.append( entry.toString( tabs + "    " ) ).append( '\n' );
234                }
235    
236                sb.append( tabs + "}" );
237            }
238    
239            return sb.toString();
240        }
241    }