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.List; 027 028import org.apache.directory.api.asn1.Asn1Object; 029import org.apache.directory.api.asn1.EncoderException; 030import org.apache.directory.api.asn1.ber.tlv.TLV; 031import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 032import org.apache.directory.api.util.Strings; 033import org.apache.directory.server.i18n.I18n; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037 038/** 039 * Store a list of METHOD-DATA 040 * 041 * The ASN.1 grammar is : 042 * <pre> 043 * METHOD-DATA ::= SEQUENCE OF <PA-DATA> 044 * </pre> 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 */ 047public class MethodData implements Asn1Object 048{ 049 /** The logger */ 050 private static final Logger LOG = LoggerFactory.getLogger( MethodData.class ); 051 052 /** Speedup for logs */ 053 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 054 055 /** List of all PA-DATA stored */ 056 private List<PaData> paDatas; 057 058 // Storage for computed lengths 059 private int methodDataLength; 060 061 062 /** 063 * Creates a new instance of MethodData. 064 */ 065 public MethodData() 066 { 067 this.paDatas = new ArrayList<>(); 068 } 069 070 071 /** 072 * Adds an {@link PaData} to the list 073 * @param paData The PaData to add 074 */ 075 public void addPaData( PaData paData ) 076 { 077 paDatas.add( paData ); 078 } 079 080 081 /** 082 * Returns true if this {@link PaData} contains a specified {@link PaData}. 083 * 084 * @param paData The paData we are looking for in the existing list 085 * @return true if this {@link PaData} contains a specified {@link PaData}. 086 */ 087 public boolean contains( PaData paData ) 088 { 089 if ( paDatas != null ) 090 { 091 return paDatas.contains( paData ); 092 } 093 094 return false; 095 } 096 097 098 /** 099 * {@inheritDoc} 100 */ 101 @Override 102 public int hashCode() 103 { 104 int hash = 37; 105 106 if ( paDatas != null ) 107 { 108 hash = hash * 17 + paDatas.size(); 109 110 for ( PaData paData : paDatas ) 111 { 112 hash = hash * 17 + paData.hashCode(); 113 } 114 } 115 116 return hash; 117 } 118 119 120 /** 121 * Returns true if two {@link MethodData} are equal. 122 * 123 * @param that The {@link MethodData} we want to compare with the current one 124 * @return true if two {@link MethodData} are equal. 125 */ 126 public boolean equals( MethodData that ) 127 { 128 if ( that == null ) 129 { 130 return false; 131 } 132 133 // infoEntries can't be null after creation 134 if ( paDatas.size() != that.paDatas.size() ) 135 { 136 return false; 137 } 138 139 for ( int i = 0; i < paDatas.size(); i++ ) 140 { 141 if ( !paDatas.get( i ).equals( that.paDatas.get( i ) ) ) 142 { 143 return false; 144 } 145 } 146 147 return true; 148 } 149 150 151 /** 152 * Returns the contained {@link PaData}s as an array. 153 * 154 * @return An array of {@link PaData}s. 155 */ 156 public PaData[] getPaDatas() 157 { 158 return paDatas.toArray( new PaData[0] ); 159 } 160 161 162 /** 163 * Compute the METHOD-DATA length 164 * <pre> 165 * METHOD-DATA : 166 * 167 * 0x30 L1 METHOD-DATA sequence of PA-DATA 168 * | 169 * +--> 0x30 L2[1] PA-DATA[1] 170 * | 171 * +--> 0x30 L2[2] PA-DATA[2] 172 * | 173 * ... 174 * | 175 * +--> 0x30 L2[n] PA-DATA[n] 176 * 177 * where L1 = sum( L2[1], l2[2], ..., L2[n] ) 178 * </pre> 179 */ 180 public int computeLength() 181 { 182 // Compute the PA-DATA length. 183 methodDataLength = 0; 184 185 if ( ( paDatas != null ) && !paDatas.isEmpty() ) 186 { 187 for ( PaData paData : paDatas ) 188 { 189 int length = paData.computeLength(); 190 methodDataLength += length; 191 } 192 } 193 194 return 1 + TLV.getNbBytes( methodDataLength ) + methodDataLength; 195 } 196 197 198 /** 199 * Encode the METHOD-DATA message to a PDU. 200 * <pre> 201 * METHOD-DATA : 202 * 203 * 0x30 LL 204 * 0x30 LL PA-DATA[1] 205 * 0x30 LL PA-DATA[1] 206 * ... 207 * 0x30 LL PA-DATA[1] 208 * </pre> 209 * @param buffer The buffer where to put the PDU. It should have been allocated 210 * before, with the right size. 211 * @return The constructed PDU. 212 */ 213 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 214 { 215 if ( buffer == null ) 216 { 217 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 218 } 219 220 try 221 { 222 // The METHOD-DATA SEQ Tag 223 buffer.put( UniversalTag.SEQUENCE.getValue() ); 224 buffer.put( TLV.getBytes( methodDataLength ) ); 225 226 // The PA-DATA list, if it's not empty 227 if ( ( paDatas != null ) && !paDatas.isEmpty() ) 228 { 229 for ( PaData paData : paDatas ) 230 { 231 paData.encode( buffer ); 232 } 233 } 234 } 235 catch ( BufferOverflowException boe ) 236 { 237 LOG.error( I18n.err( I18n.ERR_144, 1 + TLV.getNbBytes( methodDataLength ) 238 + methodDataLength, buffer.capacity() ) ); 239 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 240 } 241 242 if ( IS_DEBUG ) 243 { 244 LOG.debug( "METHOD-DATA encoding : {}", Strings.dumpBytes( buffer.array() ) ); 245 LOG.debug( "METHOD-DATA initial value : {}", this ); 246 } 247 248 return buffer; 249 } 250 251 252 /** 253 * @see Object#toString() 254 */ 255 public String toString() 256 { 257 StringBuilder sb = new StringBuilder(); 258 boolean isFirst = true; 259 260 sb.append( "METHOD-DATA : " ); 261 262 for ( PaData paData : paDatas ) 263 { 264 if ( isFirst ) 265 { 266 isFirst = false; 267 } 268 else 269 { 270 sb.append( ", " ); 271 } 272 273 sb.append( paData.toString() ); 274 } 275 276 return sb.toString(); 277 } 278}