001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.plugins.profiler; 028 029import java.io.IOException; 030 031import org.forgerock.i18n.slf4j.LocalizedLogger; 032import org.forgerock.opendj.io.ASN1Reader; 033import org.forgerock.opendj.io.ASN1Writer; 034 035/** 036 * This class defines a data structure that may be used to hold information 037 * about a thread stack trace. 038 */ 039public class ProfileStack 040{ 041 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 042 043 044 045 046 /** 047 * The line number that will be used for stack frames in which the line number 048 * is unknown but it is not a native method. 049 */ 050 public static final int LINE_NUMBER_UNKNOWN = -1; 051 052 053 054 /** 055 * The line number that will be used for stack frames in which the line number 056 * is unknown because it is a native method. 057 */ 058 public static final int LINE_NUMBER_NATIVE = -2; 059 060 061 062 /** The number of frames in this stack. */ 063 private int numFrames; 064 065 /** The source file line numbers for each of the frames in this stack. */ 066 private int[] lineNumbers; 067 068 /** The class names for each of the frames in this stack. */ 069 private String[] classNames; 070 071 /** The method names for each of the frames in this stack. */ 072 private String[] methodNames; 073 074 075 076 /** 077 * Creates a new profile stack with the provided information. 078 * 079 * @param stackElements The stack trace elements to use to create this 080 * profile stack. 081 */ 082 public ProfileStack(StackTraceElement[] stackElements) 083 { 084 numFrames = stackElements.length; 085 classNames = new String[numFrames]; 086 methodNames = new String[numFrames]; 087 lineNumbers = new int[numFrames]; 088 089 for (int i=0, j=numFrames-1; i < numFrames; i++,j--) 090 { 091 classNames[i] = stackElements[j].getClassName(); 092 methodNames[i] = stackElements[j].getMethodName(); 093 lineNumbers[i] = stackElements[j].getLineNumber(); 094 095 if (lineNumbers[i] <= 0) 096 { 097 if (stackElements[j].isNativeMethod()) 098 { 099 lineNumbers[i] = LINE_NUMBER_NATIVE; 100 } 101 else 102 { 103 lineNumbers[i] = LINE_NUMBER_UNKNOWN; 104 } 105 } 106 } 107 } 108 109 110 111 /** 112 * Creates a new profile stack with the provided information. 113 * 114 * @param classNames The class names for the frames in this stack. 115 * @param methodNames The method names for the frames in this stack. 116 * @param lineNumbers The line numbers for the frames in this stack. 117 */ 118 private ProfileStack(String[] classNames, String[] methodNames, 119 int[] lineNumbers) 120 { 121 this.numFrames = classNames.length; 122 this.classNames = classNames; 123 this.methodNames = methodNames; 124 this.lineNumbers = lineNumbers; 125 } 126 127 128 129 /** 130 * Retrieves the number of frames in this stack. 131 * 132 * @return The number of frames in this stack. 133 */ 134 public int getNumFrames() 135 { 136 return numFrames; 137 } 138 139 140 141 /** 142 * Retrieves the class names in this stack. 143 * 144 * @return The class names in this stack. 145 */ 146 public String[] getClassNames() 147 { 148 return classNames; 149 } 150 151 152 153 /** 154 * Retrieves the class name from the specified frame in the stack. 155 * 156 * @param depth The depth of the frame to retrieve, with the first frame 157 * being frame zero. 158 * 159 * @return The class name from the specified frame in the stack. 160 */ 161 public String getClassName(int depth) 162 { 163 return classNames[depth]; 164 } 165 166 167 168 /** 169 * Retrieves the method names in this stack. 170 * 171 * @return The method names in this stack. 172 */ 173 public String[] getMethodNames() 174 { 175 return methodNames; 176 } 177 178 179 180 /** 181 * Retrieves the method name from the specified frame in the stack. 182 * 183 * @param depth The depth of the frame to retrieve, with the first frame 184 * being frame zero. 185 * 186 * @return The method name from the specified frame in the stack. 187 */ 188 public String getMethodName(int depth) 189 { 190 return methodNames[depth]; 191 } 192 193 194 195 /** 196 * Retrieves the line numbers in this stack. 197 * 198 * @return The line numbers in this stack. 199 */ 200 public int[] getLineNumbers() 201 { 202 return lineNumbers; 203 } 204 205 206 207 /** 208 * Retrieves the line number from the specified frame in the stack. 209 * 210 * @param depth The depth of the frame for which to retrieve the line 211 * number. 212 * 213 * @return The line number from the specified frame in the stack. 214 */ 215 public int getLineNumber(int depth) 216 { 217 return lineNumbers[depth]; 218 } 219 220 221 222 /** 223 * Retrieves the hash code for this profile stack. It will be the sum of the 224 * hash codes for the class and method name and line number for the first 225 * frame. 226 * 227 * @return The hash code for this profile stack. 228 */ 229 public int hashCode() 230 { 231 if (numFrames != 0) 232 { 233 return classNames[0].hashCode() + methodNames[0].hashCode() + lineNumbers[0]; 234 } 235 return 0; 236 } 237 238 239 240 /** 241 * Indicates whether to the provided object is equal to this profile stack. 242 * 243 * @param o The object for which to make the determination. 244 * 245 * @return <CODE>true</CODE> if the provided object is a profile stack object 246 * with the same set of class names, method names, and line numbers 247 * as this profile stack, or <CODE>false</CODE> if not. 248 */ 249 public boolean equals(Object o) 250 { 251 if (o == null) 252 { 253 return false; 254 } 255 else if (this == o) 256 { 257 return true; 258 } 259 260 261 try 262 { 263 ProfileStack s = (ProfileStack) o; 264 265 if (numFrames != s.numFrames) 266 { 267 return false; 268 } 269 270 for (int i=0; i < numFrames; i++) 271 { 272 if (lineNumbers[i] != s.lineNumbers[i] || 273 !classNames[i].equals(s.classNames[i]) || 274 !methodNames[i].equals(s.methodNames[i])) 275 { 276 return false; 277 } 278 } 279 280 return true; 281 } 282 catch (Exception e) 283 { 284 logger.traceException(e); 285 286 return false; 287 } 288 } 289 290 291 292 /** 293 * Encodes and writes this profile stack to the capture file. 294 * 295 * @param writer The writer to use. 296 * @throws IOException if an error occurs while writing. 297 */ 298 public void write(ASN1Writer writer) throws IOException 299 { 300 writer.writeStartSequence(); 301 writer.writeInteger(numFrames); 302 for (int i=0; i < numFrames; i++) 303 { 304 writer.writeOctetString(classNames[i]); 305 writer.writeOctetString(methodNames[i]); 306 writer.writeInteger(lineNumbers[i]); 307 } 308 writer.writeEndSequence(); 309 } 310 311 312 313 /** 314 * Decodes the contents of the provided element as a profile stack. 315 * 316 * @param reader The ASN.1 reader to read the encoded profile stack 317 * information from. 318 * 319 * @return The decoded profile stack. 320 * @throws IOException If the element could not be decoded for some reason. 321 */ 322 public static ProfileStack decode(ASN1Reader reader) throws IOException 323 { 324 reader.readStartSequence(); 325 326 int numFrames = (int)reader.readInteger(); 327 String[] classNames = new String[numFrames]; 328 String[] methodNames = new String[numFrames]; 329 int[] lineNumbers = new int[numFrames]; 330 331 int i = 0; 332 while(reader.hasNextElement()) 333 { 334 classNames[i] = reader.readOctetStringAsString(); 335 methodNames[i] = reader.readOctetStringAsString(); 336 lineNumbers[i] = (int)reader.readInteger(); 337 i++; 338 } 339 340 reader.readEndSequence(); 341 342 return new ProfileStack(classNames, methodNames, lineNumbers); 343 } 344} 345