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