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.Arrays;
027    import java.util.List;
028    
029    import org.apache.directory.server.i18n.I18n;
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     * Store a list of addresses.
041     * 
042     * The ASN.1 grammar is :
043     * 
044     * -- NOTE: HostAddresses is always used as an OPTIONAL field and
045     * -- should not be empty.
046     * HostAddresses   -- NOTE: subtly different from rfc1510,
047     *                 -- but has a value mapping and encodes the same
048     *         ::= SEQUENCE OF HostAddress
049     *
050     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051     * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $
052     */
053    public class HostAddresses extends AbstractAsn1Object
054    {
055        /** The logger */
056        private static final Logger LOG = LoggerFactory.getLogger( HostAddresses.class );
057    
058        /** Speedup for logs */
059        private static final boolean IS_DEBUG = LOG.isDebugEnabled();
060    
061        /** List of all HostAddress stored */
062        private List<HostAddress> addresses;
063    
064        // Storage for computed lengths
065        private transient int addressesLength;
066    
067    
068        /**
069         * Creates a new instance of HostAddresses.
070         */
071        public HostAddresses()
072        {
073            this.addresses = new ArrayList<HostAddress>();
074        }
075        
076    
077        /**
078         * Creates a new instance of HostAddresses.
079         *
080         * @param addresses The associated addresses
081         */
082        public HostAddresses( HostAddress[] addresses )
083        {
084            if ( addresses == null )
085            {
086                this.addresses = new ArrayList<HostAddress>();
087            }
088            else
089            {
090                this.addresses = Arrays.asList( addresses );
091            }
092        }
093    
094    
095        public void addHostAddress( HostAddress hostAddress )
096        {
097            addresses.add( hostAddress );
098        }
099    
100    
101        /**
102         * Returns true if this {@link HostAddresses} contains a specified {@link HostAddress}.
103         *
104         * @param address
105         * @return true if this {@link HostAddresses} contains a specified {@link HostAddress}.
106         */
107        public boolean contains( HostAddress address )
108        {
109            if ( addresses != null )
110            {
111                return addresses.contains( address );
112            }
113    
114            return false;
115        }
116    
117    
118        /**
119         * Returns true if two {@link HostAddresses} are equal.
120         *
121         * @param that
122         * @return true if two {@link HostAddresses} are equal.
123         */
124        public boolean equals( HostAddresses that )
125        {
126            if ( ( addresses == null && that.addresses != null )
127                || ( addresses != null && that.addresses == null ) )
128            {
129                return false;
130            }
131    
132            if ( addresses != null && that.addresses != null )
133            {
134                if ( addresses.size() != that.addresses.size() )
135                {
136                    return false;
137                }
138    
139                HostAddress[] thisHostAddresses = ( HostAddress[] ) addresses.toArray();
140                HostAddress[] thatHostAddresses = ( HostAddress[] ) that.addresses.toArray();
141    
142                for ( int i = 0; i < thisHostAddresses.length; i++ )
143                {
144                    if ( !thisHostAddresses[i].equals( thatHostAddresses[i] ) )
145                    {
146                        return false;
147                    }
148                }
149            }
150    
151            return true;
152        }
153    
154    
155        /**
156         * Returns the contained {@link HostAddress}s as an array.
157         *
158         * @return An array of {@link HostAddress}s.
159         */
160        public HostAddress[] getAddresses()
161        {
162            return ( HostAddress[] ) addresses.toArray();
163        }
164    
165    
166        /**
167         * Compute the hostAddresses length
168         * 
169         * HostAddresses :
170         * 
171         * 0x30 L1 hostAddresses sequence of HostAddresses
172         *  |
173         *  +--> 0x30 L2[1] Hostaddress[1]
174         *  |
175         *  +--> 0x30 L2[2] Hostaddress[2]
176         *  |
177         *  ...
178         *  |
179         *  +--> 0x30 L2[n] Hostaddress[n]
180         *        
181         *  where L1 = sum( L2[1], l2[2], ..., L2[n] )
182         */
183        public int computeLength()
184        {
185            // Compute the addresses length.
186            addressesLength = 0;
187    
188            if ( ( addresses != null ) && ( addresses.size() != 0 ) )
189            {
190                for ( HostAddress hostAddress : addresses )
191                {
192                    int length = hostAddress.computeLength();
193                    addressesLength += length;
194                }
195            }
196    
197            return 1 + TLV.getNbBytes( addressesLength ) + addressesLength;
198        }
199    
200    
201        /**
202         * Encode the HostAddress message to a PDU. 
203         * 
204         * HostAddress :
205         * 
206         * 0x30 LL
207         *   0x30 LL hostaddress[1] 
208         *   0x30 LL hostaddress[1]
209         *   ... 
210         *   0x30 LL hostaddress[1] 
211         * 
212         * @param buffer The buffer where to put the PDU. It should have been allocated
213         * before, with the right size.
214         * @return The constructed PDU.
215         */
216        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
217        {
218            if ( buffer == null )
219            {
220                throw new EncoderException( I18n.err( I18n.ERR_148 ) );
221            }
222    
223            try
224            {
225                // The HostAddresses SEQ Tag
226                buffer.put( UniversalTag.SEQUENCE_TAG );
227                buffer.put( TLV.getBytes( addressesLength ) );
228    
229                // The hostAddress list, if it's not empty
230                if ( ( addresses != null ) && ( addresses.size() != 0 ) )
231                {
232                    for ( HostAddress hostAddress : addresses )
233                    {
234                        hostAddress.encode( buffer );
235                    }
236                }
237            }
238            catch ( BufferOverflowException boe )
239            {
240                LOG.error( I18n.err( I18n.ERR_144, 1 + TLV.getNbBytes( addressesLength )
241                    + addressesLength, buffer.capacity() ) );
242                throw new EncoderException( I18n.err( I18n.ERR_138 ) );
243            }
244    
245            if ( IS_DEBUG )
246            {
247                LOG.debug( "HostAddresses encoding : {}", StringTools.dumpBytes( buffer.array() ) );
248                LOG.debug( "HostAddresses initial value : {}", toString() );
249            }
250    
251            return buffer;
252        }
253    
254    
255        /**
256         * @see Object#toString()
257         */
258        public String toString()
259        {
260            StringBuilder sb = new StringBuilder();
261            boolean isFirst = true;
262    
263            for ( HostAddress hostAddress : addresses )
264            {
265                if ( isFirst )
266                {
267                    isFirst = false;
268                }
269                else
270                {
271                    sb.append( ", " );
272                }
273    
274                sb.append( hostAddress.toString() );
275            }
276    
277            return sb.toString();
278        }
279    }