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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.plugins.profiler; 028 029 030 031 import java.util.ArrayList; 032 import org.opends.server.protocols.asn1.ASN1Element; 033 import org.opends.server.protocols.asn1.ASN1OctetString; 034 import org.opends.server.protocols.asn1.ASN1Sequence; 035 036 import static org.opends.server.loggers.debug.DebugLogger.*; 037 import org.opends.server.loggers.debug.DebugTracer; 038 import org.opends.server.types.DebugLogLevel; 039 040 041 /** 042 * This class defines a data structure that may be used to hold information 043 * about a thread stack trace. 044 */ 045 public class ProfileStack 046 { 047 /** 048 * The tracer object for the debug logger. 049 */ 050 private static final DebugTracer TRACER = getTracer(); 051 052 053 054 055 /** 056 * The line number that will be used for stack frames in which the line number 057 * is unknown but it is not a native method. 058 */ 059 public static final int LINE_NUMBER_UNKNOWN = -1; 060 061 062 063 /** 064 * The line number that will be used for stack frames in which the line number 065 * is unknown because it is a native method. 066 */ 067 public static final int LINE_NUMBER_NATIVE = -2; 068 069 070 071 // The number of frames in this stack. 072 private int numFrames; 073 074 // The source file line numbers for each of the frames in this stack. 075 private int[] lineNumbers; 076 077 // The class names for each of the frames in this stack. 078 private String[] classNames; 079 080 // The method names for each of the frames in this stack. 081 private String[] methodNames; 082 083 084 085 /** 086 * Creates a new profile stack with the provided information. 087 * 088 * @param stackElements The stack trace elements to use to create this 089 * profile stack. 090 */ 091 public ProfileStack(StackTraceElement[] stackElements) 092 { 093 numFrames = stackElements.length; 094 classNames = new String[numFrames]; 095 methodNames = new String[numFrames]; 096 lineNumbers = new int[numFrames]; 097 098 for (int i=0, j=(numFrames-1); i < numFrames; i++,j--) 099 { 100 classNames[i] = stackElements[j].getClassName(); 101 methodNames[i] = stackElements[j].getMethodName(); 102 lineNumbers[i] = stackElements[j].getLineNumber(); 103 104 if (lineNumbers[i] <= 0) 105 { 106 if (stackElements[j].isNativeMethod()) 107 { 108 lineNumbers[i] = LINE_NUMBER_NATIVE; 109 } 110 else 111 { 112 lineNumbers[i] = LINE_NUMBER_UNKNOWN; 113 } 114 } 115 } 116 } 117 118 119 120 /** 121 * Creates a new profile stack with the provided information. 122 * 123 * @param classNames The class names for the frames in this stack. 124 * @param methodNames The method names for the frames in this stack. 125 * @param lineNumbers The line numbers for the frames in this stack. 126 */ 127 private ProfileStack(String[] classNames, String[] methodNames, 128 int[] lineNumbers) 129 { 130 this.numFrames = classNames.length; 131 this.classNames = classNames; 132 this.methodNames = methodNames; 133 this.lineNumbers = lineNumbers; 134 } 135 136 137 138 /** 139 * Retrieves the number of frames in this stack. 140 * 141 * @return The number of frames in this stack. 142 */ 143 public int getNumFrames() 144 { 145 return numFrames; 146 } 147 148 149 150 /** 151 * Retrieves the class names in this stack. 152 * 153 * @return The class names in this stack. 154 */ 155 public String[] getClassNames() 156 { 157 return classNames; 158 } 159 160 161 162 /** 163 * Retrieves the class name from the specified frame in the stack. 164 * 165 * @param depth The depth of the frame to retrieve, with the first frame 166 * being frame zero. 167 * 168 * @return The class name from the specified frame in the stack. 169 */ 170 public String getClassName(int depth) 171 { 172 return classNames[depth]; 173 } 174 175 176 177 /** 178 * Retrieves the method names in this stack. 179 * 180 * @return The method names in this stack. 181 */ 182 public String[] getMethodNames() 183 { 184 return methodNames; 185 } 186 187 188 189 /** 190 * Retrieves the method name from the specified frame in the stack. 191 * 192 * @param depth The depth of the frame to retrieve, with the first frame 193 * being frame zero. 194 * 195 * @return The method name from the specified frame in the stack. 196 */ 197 public String getMethodName(int depth) 198 { 199 return methodNames[depth]; 200 } 201 202 203 204 /** 205 * Retrieves the line numbers in this stack. 206 * 207 * @return The line numbers in this stack. 208 */ 209 public int[] getLineNumbers() 210 { 211 return lineNumbers; 212 } 213 214 215 216 /** 217 * Retrieves the line number from the specified frame in the stack. 218 * 219 * @param depth The depth of the frame for which to retrieve the line 220 * number. 221 * 222 * @return The line number from the specified frame in the stack. 223 */ 224 public int getLineNumber(int depth) 225 { 226 return lineNumbers[depth]; 227 } 228 229 230 231 /** 232 * Retrieves the hash code for this profile stack. It will be the sum of the 233 * hash codes for the class and method name and line number for the first 234 * frame. 235 * 236 * @return The hash code for this profile stack. 237 */ 238 public int hashCode() 239 { 240 if (numFrames == 0) 241 { 242 return 0; 243 } 244 else 245 { 246 return (classNames[0].hashCode() + methodNames[0].hashCode() + 247 lineNumbers[0]); 248 } 249 } 250 251 252 253 /** 254 * Indicates whether to the provided object is equal to this profile stack. 255 * 256 * @param o The object for which to make the determination. 257 * 258 * @return <CODE>true</CODE> if the provided object is a profile stack object 259 * with the same set of class names, method names, and line numbers 260 * as this profile stack, or <CODE>false</CODE> if not. 261 */ 262 public boolean equals(Object o) 263 { 264 if (o == null) 265 { 266 return false; 267 } 268 else if (this == o) 269 { 270 return true; 271 } 272 273 274 try 275 { 276 ProfileStack s = (ProfileStack) o; 277 278 if (numFrames != s.numFrames) 279 { 280 return false; 281 } 282 283 for (int i=0; i < numFrames; i++) 284 { 285 if ((lineNumbers[i] != s.lineNumbers[i]) || 286 (! classNames[i].equals(s.classNames[i])) || 287 (! methodNames[i].equals(s.methodNames[i]))) 288 { 289 return false; 290 } 291 } 292 293 return true; 294 } 295 catch (Exception e) 296 { 297 if (debugEnabled()) 298 { 299 TRACER.debugCaught(DebugLogLevel.ERROR, e); 300 } 301 302 return false; 303 } 304 } 305 306 307 308 /** 309 * Encodes this profile stack for writing to the capture file. 310 * 311 * @return The ASN.1 element containing the encoded representation of this 312 * profile stack. 313 */ 314 public ASN1Element encode() 315 { 316 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3*numFrames); 317 for (int i=0; i < numFrames; i++) 318 { 319 elements.add(new ASN1OctetString(classNames[i])); 320 elements.add(new ASN1OctetString(methodNames[i])); 321 elements.add(new ASN1OctetString(String.valueOf(lineNumbers[i]))); 322 } 323 324 return new ASN1Sequence(elements); 325 } 326 327 328 329 /** 330 * Decodes the contents of the provided element as a profile stack. 331 * 332 * @param stackElement The ASN.1 element containing the encoded profile 333 * stack information. 334 * 335 * @return The decoded profile stack, or <CODE>null</CODE> if the element 336 * could not be decoded for some reason. 337 */ 338 public static ProfileStack decode(ASN1Element stackElement) 339 { 340 try 341 { 342 ArrayList<ASN1Element> elements = 343 stackElement.decodeAsSequence().elements(); 344 345 int numFrames = (elements.size() / 3); 346 String[] classNames = new String[numFrames]; 347 String[] methodNames = new String[numFrames]; 348 int[] lineNumbers = new int[numFrames]; 349 350 for (int i=0,j=0; i < numFrames; i++, j+=3) 351 { 352 classNames[i] = elements.get(j).decodeAsOctetString().stringValue(); 353 methodNames[i] = elements.get(j+1).decodeAsOctetString().stringValue(); 354 lineNumbers[i] = 355 Integer.parseInt( 356 elements.get(j+2).decodeAsOctetString().stringValue()); 357 } 358 359 return new ProfileStack(classNames, methodNames, lineNumbers); 360 } 361 catch (Exception e) 362 { 363 if (debugEnabled()) 364 { 365 TRACER.debugCaught(DebugLogLevel.ERROR, e); 366 } 367 368 return null; 369 } 370 } 371 } 372