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-INFO2.
41   * 
42   * The ASN.1 grammar is :
43   * <pre>
44   * ETYPE-INFO2              ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY
45   *</pre>
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   */
48  public class ETypeInfo2 implements Asn1Object
49  {
50      /** The logger */
51      private static final Logger LOG = LoggerFactory.getLogger( ETypeInfo2.class );
52  
53      /** Speedup for logs */
54      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
55  
56      /** List of all ETYPE-INFO2-ENTRY stored */
57      private List<ETypeInfo2Entry> etypeInfo2Entries;
58  
59      // Storage for computed lengths
60      private int etypeInfo2Length;
61  
62  
63      /**
64       * Creates a new instance of ETypeInfo2.
65       */
66      public ETypeInfo2()
67      {
68          this.etypeInfo2Entries = new ArrayList<>();
69      }
70  
71  
72      /**
73       * Creates a new instance of ETypeInfo2.
74       *
75       * @param etypeInfo2Entries The associated etypeInfo2Entries
76       */
77      public ETypeInfo2( ETypeInfo2Entry[] etypeInfo2Entries )
78      {
79          if ( etypeInfo2Entries == null )
80          {
81              this.etypeInfo2Entries = new ArrayList<>();
82          }
83          else
84          {
85              this.etypeInfo2Entries = Arrays.asList( etypeInfo2Entries );
86          }
87      }
88  
89  
90      /**
91       * Adds an {@link ETypeInfo2Entry} to the list
92       * @param etypeInfo2Entry The ETypeInfo2Entry to add
93       */
94      public void addETypeInfo2Entry( ETypeInfo2Entry etypeInfo2Entry )
95      {
96          etypeInfo2Entries.add( etypeInfo2Entry );
97      }
98  
99  
100     /**
101      * Returns true if this {@link ETypeInfo2Entry} contains a specified {@link ETypeInfo2Entry}.
102      *
103      * @param etypeInfo2Entry The etypeInfo2Entry we are looking for in the existing list
104      * @return true if this {@link ETypeInfo2Entry} contains a specified {@link ETypeInfo2Entry}.
105      */
106     public boolean contains( ETypeInfo2Entry etypeInfo2Entry )
107     {
108         if ( etypeInfo2Entries != null )
109         {
110             return etypeInfo2Entries.contains( etypeInfo2Entry );
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 ( etypeInfo2Entries != null )
126         {
127             hash = hash * 17 + etypeInfo2Entries.size();
128 
129             for ( ETypeInfo2Entry etypeInfo2Entry : etypeInfo2Entries )
130             {
131                 hash = hash * 17 + etypeInfo2Entry.hashCode();
132             }
133         }
134 
135         return hash;
136     }
137 
138 
139     /**
140      * Returns true if two {@link ETypeInfo2} are equal.
141      *
142      * @param that The {@link ETypeInfo2} we want to compare with the current one
143      * @return true if two {@link ETypeInfo2} are equal.
144      */
145     public boolean equals( ETypeInfo2 that )
146     {
147         if ( that == null )
148         {
149             return false;
150         }
151 
152         // infoEntries can't be null after creation
153         if ( etypeInfo2Entries.size() != that.etypeInfo2Entries.size() )
154         {
155             return false;
156         }
157 
158         for ( int i = 0; i < etypeInfo2Entries.size(); i++ )
159         {
160             if ( !etypeInfo2Entries.get( i ).equals( that.etypeInfo2Entries.get( i ) ) )
161             {
162                 return false;
163             }
164         }
165 
166         return true;
167     }
168 
169 
170     /**
171      * Returns the contained {@link ETypeInfo2Entry}s as an array.
172      *
173      * @return An array of {@link ETypeInfo2Entry}s.
174      */
175     public ETypeInfo2Entry[] getETypeInfo2Entries()
176     {
177         return etypeInfo2Entries.toArray( new ETypeInfo2Entry[0] );
178     }
179 
180 
181     /**
182      * Compute the ETypeInfo2 length
183      * <pre>
184      * ETypeInfo2 :
185      * 
186      * 0x30 L1 ETypeInfo2 sequence of ETypeInfo2Entry
187      *  |
188      *  +--&gt; 0x30 L2[1] ETypeInfo2Entry[1]
189      *  |
190      *  +--&gt; 0x30 L2[2] ETypeInfo2Entry[2]
191      *  |
192      *  ...
193      *  |
194      *  +--&gt; 0x30 L2[n] ETypeInfo2Entry[n]
195      *        
196      *  where L1 = sum( L2[1], l2[2], ..., L2[n] )
197      * </pre>
198      */
199     public int computeLength()
200     {
201         // Compute the ETypeInfo2 length.
202         etypeInfo2Length = 0;
203 
204         if ( ( etypeInfo2Entries != null ) && !etypeInfo2Entries.isEmpty() )
205         {
206             for ( ETypeInfo2Entry info2Entry : etypeInfo2Entries )
207             {
208                 int length = info2Entry.computeLength();
209                 etypeInfo2Length += length;
210             }
211         }
212 
213         return 1 + TLV.getNbBytes( etypeInfo2Length ) + etypeInfo2Length;
214     }
215 
216 
217     /**
218      * Encode the ETypeInfo2 message to a PDU. 
219      * <pre>
220      * ETypeInfo2 :
221      * 
222      * 0x30 LL
223      *   0x30 LL ETypeInfo2Entry[1] 
224      *   0x30 LL ETypeInfo2Entry[1]
225      *   ... 
226      *   0x30 LL ETypeInfo2Entry[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 ETypeInfo2Entry SEQ Tag
242             buffer.put( UniversalTag.SEQUENCE.getValue() );
243             buffer.put( TLV.getBytes( etypeInfo2Length ) );
244 
245             // The ETypeInfo2Entry list, if it's not empty
246             if ( ( etypeInfo2Entries != null ) && !etypeInfo2Entries.isEmpty() )
247             {
248                 for ( ETypeInfo2Entry info2Entry : etypeInfo2Entries )
249                 {
250                     info2Entry.encode( buffer );
251                 }
252             }
253         }
254         catch ( BufferOverflowException boe )
255         {
256             LOG.error( I18n.err( I18n.ERR_144, 1 + TLV.getNbBytes( etypeInfo2Length )
257                 + etypeInfo2Length, 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 ( ETypeInfo2Entry info2Entry : etypeInfo2Entries )
280         {
281             if ( isFirst )
282             {
283                 isFirst = false;
284             }
285             else
286             {
287                 sb.append( ", " );
288             }
289 
290             sb.append( info2Entry.toString() );
291         }
292 
293         return sb.toString();
294     }
295 }