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 ETYPE-INFO
41   * 
42   * The ASN.1 grammar is :
43   * <pre>
44   * ETYPE-INFO              ::= SEQUENCE OF &lt;ETYPE-INFO-ENTRY&gt;
45   * </pre>
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   */
48  public class ETypeInfo implements Asn1Object
49  {
50      /** The logger */
51      private static final Logger LOG = LoggerFactory.getLogger( ETypeInfo.class );
52  
53      /** Speedup for logs */
54      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
55  
56      /** List of all ETYPE-INFO-ENTRY stored */
57      private List<ETypeInfoEntry> etypeInfoEntries;
58  
59      // Storage for computed lengths
60      private int etypeInfoLength;
61  
62  
63      /**
64       * Creates a new instance of ETypeInfo.
65       */
66      public ETypeInfo()
67      {
68          this.etypeInfoEntries = new ArrayList<>();
69      }
70  
71  
72      /**
73       * Creates a new instance of ETypeInfo.
74       *
75       * @param etypeInfoEntries The associated etypeInfoEntries
76       */
77      public ETypeInfo( ETypeInfoEntry[] etypeInfoEntries )
78      {
79          if ( etypeInfoEntries == null )
80          {
81              this.etypeInfoEntries = new ArrayList<>();
82          }
83          else
84          {
85              this.etypeInfoEntries = Arrays.asList( etypeInfoEntries );
86          }
87      }
88  
89  
90      /**
91       * Adds an {@link ETypeInfoEntry} to the list
92       * @param etypeInfoEntry The ETypeInfoEntry to add
93       */
94      public void addETypeInfoEntry( ETypeInfoEntry etypeInfoEntry )
95      {
96          etypeInfoEntries.add( etypeInfoEntry );
97      }
98  
99  
100     /**
101      * Returns true if this {@link ETypeInfoEntry} contains a specified {@link ETypeInfoEntry}.
102      *
103      * @param etypeInfoEntry The etypeInfoEntry we are looking for in the existing list
104      * @return true if this {@link ETypeInfoEntry} contains a specified {@link ETypeInfoEntry}.
105      */
106     public boolean contains( ETypeInfoEntry etypeInfoEntry )
107     {
108         if ( etypeInfoEntries != null )
109         {
110             return etypeInfoEntries.contains( etypeInfoEntry );
111         }
112 
113         return false;
114     }
115 
116 
117     /**
118      * {@inheritDoc}
119      */
120     @Override
121     public int hashCode()
122     {
123         int hash = 37;
124 
125         if ( etypeInfoEntries != null )
126         {
127             hash = hash * 17 + etypeInfoEntries.size();
128 
129             for ( ETypeInfoEntry etypeInfoEntry : etypeInfoEntries )
130             {
131                 hash = hash * 17 + etypeInfoEntry.hashCode();
132             }
133         }
134 
135         return hash;
136     }
137 
138 
139     /**
140      * Returns true if two {@link ETypeInfo} are equal.
141      *
142      * @param that The {@link ETypeInfo} we want to compare with the current one
143      * @return true if two {@link ETypeInfo} are equal.
144      */
145     public boolean equals( ETypeInfo that )
146     {
147         if ( that == null )
148         {
149             return false;
150         }
151 
152         // infoEntries can't be null after creation
153         if ( etypeInfoEntries.size() != that.etypeInfoEntries.size() )
154         {
155             return false;
156         }
157 
158         for ( int i = 0; i < etypeInfoEntries.size(); i++ )
159         {
160             if ( !etypeInfoEntries.get( i ).equals( that.etypeInfoEntries.get( i ) ) )
161             {
162                 return false;
163             }
164         }
165 
166         return true;
167     }
168 
169 
170     /**
171      * Returns the contained {@link ETypeInfoEntry}s as an array.
172      *
173      * @return An array of {@link ETypeInfoEntry}s.
174      */
175     public ETypeInfoEntry[] getETypeInfoEntries()
176     {
177         return etypeInfoEntries.toArray( new ETypeInfoEntry[0] );
178     }
179 
180 
181     /**
182      * Compute the ETypeInfo length
183      * <pre>
184      * ETypeInfo :
185      * 
186      * 0x30 L1 ETypeInfo sequence of ETypeInfoEntry
187      *  |
188      *  +--&gt; 0x30 L2[1] ETypeInfoEntry[1]
189      *  |
190      *  +--&gt; 0x30 L2[2] ETypeInfoEntry[2]
191      *  |
192      *  ...
193      *  |
194      *  +--&gt; 0x30 L2[n] ETypeInfoEntry[n]
195      *        
196      *  where L1 = sum( L2[1], l2[2], ..., L2[n] )
197      * </pre>
198      */
199     public int computeLength()
200     {
201         // Compute the ETypeInfo length.
202         etypeInfoLength = 0;
203 
204         if ( ( etypeInfoEntries != null ) && !etypeInfoEntries.isEmpty() )
205         {
206             for ( ETypeInfoEntry infoEntry : etypeInfoEntries )
207             {
208                 int length = infoEntry.computeLength();
209                 etypeInfoLength += length;
210             }
211         }
212 
213         return 1 + TLV.getNbBytes( etypeInfoLength ) + etypeInfoLength;
214     }
215 
216 
217     /**
218      * Encode the ETypeInfo message to a PDU. 
219      * <pre>
220      * ETypeInfo :
221      * 
222      * 0x30 LL
223      *   0x30 LL ETypeInfoEntry[1] 
224      *   0x30 LL ETypeInfoEntry[1]
225      *   ... 
226      *   0x30 LL ETypeInfoEntry[1] 
227      * </pre>
228      * @param buffer The buffer where to put the PDU. It should have been allocated
229      * before, with the right size.
230      * @return The constructed PDU.
231      */
232     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
233     {
234         if ( buffer == null )
235         {
236             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
237         }
238 
239         try
240         {
241             // The ETypeInfoEntry SEQ Tag
242             buffer.put( UniversalTag.SEQUENCE.getValue() );
243             buffer.put( TLV.getBytes( etypeInfoLength ) );
244 
245             // The ETypeInfoEntry list, if it's not empty
246             if ( ( etypeInfoEntries != null ) && !etypeInfoEntries.isEmpty() )
247             {
248                 for ( ETypeInfoEntry infoEntry : etypeInfoEntries )
249                 {
250                     infoEntry.encode( buffer );
251                 }
252             }
253         }
254         catch ( BufferOverflowException boe )
255         {
256             LOG.error( I18n.err( I18n.ERR_144, 1 + TLV.getNbBytes( etypeInfoLength )
257                 + etypeInfoLength, buffer.capacity() ) );
258             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
259         }
260 
261         if ( IS_DEBUG )
262         {
263             LOG.debug( "ETYPE-INFO encoding : {}", Strings.dumpBytes( buffer.array() ) );
264             LOG.debug( "ETYPE-INFO initial value : {}", this );
265         }
266 
267         return buffer;
268     }
269 
270 
271     /**
272      * @see Object#toString()
273      */
274     public String toString()
275     {
276         StringBuilder sb = new StringBuilder();
277         boolean isFirst = true;
278 
279         for ( ETypeInfoEntry infoEntry : etypeInfoEntries )
280         {
281             if ( isFirst )
282             {
283                 isFirst = false;
284             }
285             else
286             {
287                 sb.append( ", " );
288             }
289 
290             sb.append( infoEntry.toString() );
291         }
292 
293         return sb.toString();
294     }
295 }