View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.shared.kerberos.components;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.List;
28  
29  import org.apache.directory.api.asn1.Asn1Object;
30  import org.apache.directory.api.asn1.EncoderException;
31  import org.apache.directory.api.asn1.ber.tlv.TLV;
32  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
33  import org.apache.directory.api.util.Strings;
34  import org.apache.directory.server.i18n.I18n;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  
39  /**
40   * Store a list of addresses.
41   * 
42   * The ASN.1 grammar is :
43   * <pre>
44   * -- NOTE: HostAddresses is always used as an OPTIONAL field and
45   * -- should not be empty.
46   * HostAddresses   -- NOTE: subtly different from rfc1510,
47   *                 -- but has a value mapping and encodes the same
48   *         ::= SEQUENCE OF HostAddress
49   *</pre>
50   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
51   */
52  public class HostAddresses implements Asn1Object
53  {
54      /** The logger */
55      private static final Logger LOG = LoggerFactory.getLogger( HostAddresses.class );
56  
57      /** Speedup for logs */
58      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
59  
60      /** List of all HostAddress stored */
61      private List<HostAddress> addresses;
62  
63      // Storage for computed lengths
64      private int addressesLength;
65  
66  
67      /**
68       * Creates a new instance of HostAddresses.
69       */
70      public HostAddresses()
71      {
72          this.addresses = new ArrayList<>();
73      }
74  
75  
76      /**
77       * Creates a new instance of HostAddresses.
78       *
79       * @param addresses The associated addresses
80       */
81      public HostAddresses( HostAddress[] addresses )
82      {
83          if ( addresses == null )
84          {
85              this.addresses = new ArrayList<>();
86          }
87          else
88          {
89              this.addresses = Arrays.asList( addresses );
90          }
91      }
92  
93  
94      /**
95       * Adds an {@link HostAddresses} to the list
96       * @param hostAddress The address to add
97       */
98      public void addHostAddress( HostAddress hostAddress )
99      {
100         addresses.add( hostAddress );
101     }
102 
103 
104     /**
105      * Returns true if this {@link HostAddresses} contains a specified {@link HostAddress}.
106      *
107      * @param address The address we are looking for in the existing list
108      * @return true if this {@link HostAddresses} contains a specified {@link HostAddress}.
109      */
110     public boolean contains( HostAddress address )
111     {
112         if ( addresses != null )
113         {
114             return addresses.contains( address );
115         }
116 
117         return false;
118     }
119 
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public int hashCode()
126     {
127         int hash = 37;
128 
129         if ( addresses != null )
130         {
131             hash = hash * 17 + addresses.size();
132             hash = hash * 17 + addresses.hashCode();
133         }
134 
135         return hash;
136     }
137 
138 
139     /**
140      * Returns true if two {@link HostAddresses} are equal.
141      *
142      * @param obj The {@link HostAddresses} we want to compare with the current one
143      * @return true if two {@link HostAddresses} are equal.
144      */
145     @Override
146     public boolean equals( Object obj )
147     {
148         if ( this == obj )
149         {
150             return true;
151         }
152 
153         if ( !( obj instanceof HostAddresses ) )
154         {
155             return false;
156         }
157 
158         HostAddresses../../../../org/apache/directory/shared/kerberos/components/HostAddresses.html#HostAddresses">HostAddresses that = ( HostAddresses ) obj;
159 
160         // Addresses can't be null after creation
161         if ( addresses.size() != that.addresses.size() )
162         {
163             return false;
164         }
165 
166         for ( int i = 0; i < addresses.size(); i++ )
167         {
168             if ( !addresses.get( i ).equals( that.addresses.get( i ) ) )
169             {
170                 return false;
171             }
172         }
173 
174         return true;
175     }
176 
177 
178     /**
179      * Returns the contained {@link HostAddress}s as an array.
180      *
181      * @return An array of {@link HostAddress}s.
182      */
183     public HostAddress[] getAddresses()
184     {
185         return addresses.toArray( new HostAddress[0] );
186     }
187 
188 
189     /**
190      * Compute the hostAddresses length
191      * <pre>
192      * HostAddresses :
193      * 
194      * 0x30 L1 hostAddresses sequence of HostAddresses
195      *  |
196      *  +--&gt; 0x30 L2[1] Hostaddress[1]
197      *  |
198      *  +--&gt; 0x30 L2[2] Hostaddress[2]
199      *  |
200      *  ...
201      *  |
202      *  +--&gt; 0x30 L2[n] Hostaddress[n]
203      *        
204      *  where L1 = sum( L2[1], l2[2], ..., L2[n] )
205      * </pre>
206      */
207     public int computeLength()
208     {
209         // Compute the addresses length.
210         addressesLength = 0;
211 
212         if ( ( addresses != null ) && !addresses.isEmpty() )
213         {
214             for ( HostAddress hostAddress : addresses )
215             {
216                 int length = hostAddress.computeLength();
217                 addressesLength += length;
218             }
219         }
220 
221         return 1 + TLV.getNbBytes( addressesLength ) + addressesLength;
222     }
223 
224 
225     /**
226      * Encode the HostAddress message to a PDU. 
227      * <pre>
228      * HostAddress :
229      * 
230      * 0x30 LL
231      *   0x30 LL hostaddress[1] 
232      *   0x30 LL hostaddress[1]
233      *   ... 
234      *   0x30 LL hostaddress[1] 
235      * </pre>
236      * @param buffer The buffer where to put the PDU. It should have been allocated
237      * before, with the right size.
238      * @return The constructed PDU.
239      */
240     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
241     {
242         if ( buffer == null )
243         {
244             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
245         }
246 
247         try
248         {
249             // The HostAddresses SEQ Tag
250             buffer.put( UniversalTag.SEQUENCE.getValue() );
251             buffer.put( TLV.getBytes( addressesLength ) );
252 
253             // The hostAddress list, if it's not empty
254             if ( ( addresses != null ) && !addresses.isEmpty() )
255             {
256                 for ( HostAddress hostAddress : addresses )
257                 {
258                     hostAddress.encode( buffer );
259                 }
260             }
261         }
262         catch ( BufferOverflowException boe )
263         {
264             LOG.error( I18n.err( I18n.ERR_144, 1 + TLV.getNbBytes( addressesLength )
265                 + addressesLength, buffer.capacity() ) );
266             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
267         }
268 
269         if ( IS_DEBUG )
270         {
271             LOG.debug( "HostAddresses encoding : {}", Strings.dumpBytes( buffer.array() ) );
272             LOG.debug( "HostAddresses initial value : {}", this );
273         }
274 
275         return buffer;
276     }
277 
278 
279     /**
280      * @see Object#toString()
281      */
282     public String toString()
283     {
284         StringBuilder sb = new StringBuilder();
285         boolean isFirst = true;
286 
287         for ( HostAddress hostAddress : addresses )
288         {
289             if ( isFirst )
290             {
291                 isFirst = false;
292             }
293             else
294             {
295                 sb.append( ", " );
296             }
297 
298             sb.append( hostAddress.toString() );
299         }
300 
301         return sb.toString();
302     }
303 }