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 */ 020package org.apache.directory.shared.kerberos.components; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.List; 028 029import org.apache.directory.api.asn1.Asn1Object; 030import org.apache.directory.api.asn1.EncoderException; 031import org.apache.directory.api.asn1.ber.tlv.TLV; 032import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 033import org.apache.directory.api.util.Strings; 034import org.apache.directory.server.i18n.I18n; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038 039/** 040 * Store a list of ETYPE-INFO 041 * 042 * The ASN.1 grammar is : 043 * <pre> 044 * ETYPE-INFO ::= SEQUENCE OF <ETYPE-INFO-ENTRY> 045 * </pre> 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 */ 048public class ETypeInfo implements Asn1Object 049{ 050 /** The logger */ 051 private static final Logger LOG = LoggerFactory.getLogger( ETypeInfo.class ); 052 053 /** Speedup for logs */ 054 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 055 056 /** List of all ETYPE-INFO-ENTRY stored */ 057 private List<ETypeInfoEntry> etypeInfoEntries; 058 059 // Storage for computed lengths 060 private int etypeInfoLength; 061 062 063 /** 064 * Creates a new instance of ETypeInfo. 065 */ 066 public ETypeInfo() 067 { 068 this.etypeInfoEntries = new ArrayList<>(); 069 } 070 071 072 /** 073 * Creates a new instance of ETypeInfo. 074 * 075 * @param etypeInfoEntries The associated etypeInfoEntries 076 */ 077 public ETypeInfo( ETypeInfoEntry[] etypeInfoEntries ) 078 { 079 if ( etypeInfoEntries == null ) 080 { 081 this.etypeInfoEntries = new ArrayList<>(); 082 } 083 else 084 { 085 this.etypeInfoEntries = Arrays.asList( etypeInfoEntries ); 086 } 087 } 088 089 090 /** 091 * Adds an {@link ETypeInfoEntry} to the list 092 * @param etypeInfoEntry The ETypeInfoEntry to add 093 */ 094 public void addETypeInfoEntry( ETypeInfoEntry etypeInfoEntry ) 095 { 096 etypeInfoEntries.add( etypeInfoEntry ); 097 } 098 099 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 * +--> 0x30 L2[1] ETypeInfoEntry[1] 189 * | 190 * +--> 0x30 L2[2] ETypeInfoEntry[2] 191 * | 192 * ... 193 * | 194 * +--> 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}