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