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.i18n.I18n;
029    import org.apache.directory.server.kerberos.shared.messages.Encodable;
030    import org.apache.directory.shared.asn1.AbstractAsn1Object;
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.codec.EncoderException;
034    import org.apache.directory.shared.ldap.util.StringTools;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    
039    /**
040     * An authorization data container.
041     * 
042     * The ASN.1 grammar is :
043     * 
044     * -- NOTE: AuthorizationData is always used as an OPTIONAL field and
045     * -- should not be empty.
046     * AuthorizationData       ::= SEQUENCE OF AuthorizationDataEntry
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $
050     */
051    public class AuthorizationData extends AbstractAsn1Object implements Encodable
052    {
053        /** The logger */
054        private static final Logger log = LoggerFactory.getLogger( AuthorizationData.class );
055    
056        /** Speedup for logs */
057        private static final boolean IS_DEBUG = log.isDebugEnabled();
058    
059        /** The list of AuthrorizationData elements */
060        private List<AuthorizationDataEntry> entries = new ArrayList<AuthorizationDataEntry>();
061    
062        // Storage for computed lengths
063        private transient int authorizationDataLength;
064    
065    
066        /**
067         * Creates a new instance of AuthorizationData.
068         */
069        public AuthorizationData()
070        {
071            // used by ASN.1 decoder
072        }
073    
074    
075        /**
076         * Adds all {@link AuthorizationData} entries to this {@link AuthorizationData}.
077         *
078         * @param data
079         */
080        public void add( AuthorizationData data )
081        {
082            entries.addAll( data.entries );
083        }
084    
085    
086        /**
087         * Adds an {@link AuthorizationDataEntry} to this {@link AuthorizationData}.
088         *
089         * @param entry
090         */
091        public void add( AuthorizationDataEntry entry )
092        {
093            entries.add( entry );
094        }
095    
096    
097        /**
098         * @return The AuthorizationdataEntry list
099         */
100        public List<AuthorizationDataEntry> getEntries()
101        {
102            return entries;
103        }
104    
105    
106        /**
107         * Compute the AuthorizationData length
108         * 
109         * AuthorizationData :
110         * 
111         * 0x30 L1 AuthorizationData
112         *  |
113         *  +--> 0x30 L2 AuthorizationDataEntry
114         *  |
115         *  +--> 0x30 L2 AuthorizationDataEntry
116         *  |
117         *  ...
118         *  |
119         *  +--> 0x30 L2 AuthorizationDataEntry
120         */
121        public int computeLength()
122        {
123            if ( ( entries == null ) || ( entries.size() == 0 ) )
124            {
125                authorizationDataLength = 1;
126    
127                return authorizationDataLength + 1;
128            }
129            else
130            {
131                authorizationDataLength = 0;
132    
133                for ( AuthorizationDataEntry entry : entries )
134                {
135                    authorizationDataLength += entry.computeLength();
136                }
137    
138                return 1 + TLV.getNbBytes( authorizationDataLength ) + authorizationDataLength;
139            }
140        }
141    
142    
143        /**
144         * Encode the AuthorizationData message to a PDU. 
145         * 
146         * AuthorizationData :
147         * 
148         * 0x30 LL
149         *   0x30 LL AuthorizationDataEntry 
150         *   0x30 LL AuthorizationDataEntry
151         *   ... 
152         *   0x30 LL AuthorizationDataEntry 
153         * 
154         * @param buffer The buffer where to put the PDU. It should have been allocated
155         * before, with the right size.
156         * @return The constructed PDU.
157         */
158        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
159        {
160            if ( buffer == null )
161            {
162                throw new EncoderException( I18n.err( I18n.ERR_148 ) );
163            }
164    
165            try
166            {
167                // The AuthorizationData SEQ Tag
168                buffer.put( UniversalTag.SEQUENCE_TAG );
169                buffer.put( TLV.getBytes( authorizationDataLength ) );
170    
171                // Each entry, if any
172                if ( ( entries != null ) && ( entries.size() != 0 ) )
173                {
174                    for ( AuthorizationDataEntry entry : entries )
175                    {
176                        entry.encode( buffer );
177                    }
178                }
179            }
180            catch ( BufferOverflowException boe )
181            {
182                log.error( I18n.err( I18n.ERR_139, 1 + TLV.getNbBytes( authorizationDataLength ) + 
183                    authorizationDataLength, buffer.capacity() ) );
184                throw new EncoderException( I18n.err( I18n.ERR_138 ) );
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    }