/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. */ package org.opends.server.plugins.profiler; import java.io.IOException; import org.opends.server.protocols.asn1.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DebugLogLevel; /** * This class defines a data structure that may be used to hold information * about a thread stack trace. */ public class ProfileStack { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** * The line number that will be used for stack frames in which the line number * is unknown but it is not a native method. */ public static final int LINE_NUMBER_UNKNOWN = -1; /** * The line number that will be used for stack frames in which the line number * is unknown because it is a native method. */ public static final int LINE_NUMBER_NATIVE = -2; // The number of frames in this stack. private int numFrames; // The source file line numbers for each of the frames in this stack. private int[] lineNumbers; // The class names for each of the frames in this stack. private String[] classNames; // The method names for each of the frames in this stack. private String[] methodNames; /** * Creates a new profile stack with the provided information. * * @param stackElements The stack trace elements to use to create this * profile stack. */ public ProfileStack(StackTraceElement[] stackElements) { numFrames = stackElements.length; classNames = new String[numFrames]; methodNames = new String[numFrames]; lineNumbers = new int[numFrames]; for (int i=0, j=(numFrames-1); i < numFrames; i++,j--) { classNames[i] = stackElements[j].getClassName(); methodNames[i] = stackElements[j].getMethodName(); lineNumbers[i] = stackElements[j].getLineNumber(); if (lineNumbers[i] <= 0) { if (stackElements[j].isNativeMethod()) { lineNumbers[i] = LINE_NUMBER_NATIVE; } else { lineNumbers[i] = LINE_NUMBER_UNKNOWN; } } } } /** * Creates a new profile stack with the provided information. * * @param classNames The class names for the frames in this stack. * @param methodNames The method names for the frames in this stack. * @param lineNumbers The line numbers for the frames in this stack. */ private ProfileStack(String[] classNames, String[] methodNames, int[] lineNumbers) { this.numFrames = classNames.length; this.classNames = classNames; this.methodNames = methodNames; this.lineNumbers = lineNumbers; } /** * Retrieves the number of frames in this stack. * * @return The number of frames in this stack. */ public int getNumFrames() { return numFrames; } /** * Retrieves the class names in this stack. * * @return The class names in this stack. */ public String[] getClassNames() { return classNames; } /** * Retrieves the class name from the specified frame in the stack. * * @param depth The depth of the frame to retrieve, with the first frame * being frame zero. * * @return The class name from the specified frame in the stack. */ public String getClassName(int depth) { return classNames[depth]; } /** * Retrieves the method names in this stack. * * @return The method names in this stack. */ public String[] getMethodNames() { return methodNames; } /** * Retrieves the method name from the specified frame in the stack. * * @param depth The depth of the frame to retrieve, with the first frame * being frame zero. * * @return The method name from the specified frame in the stack. */ public String getMethodName(int depth) { return methodNames[depth]; } /** * Retrieves the line numbers in this stack. * * @return The line numbers in this stack. */ public int[] getLineNumbers() { return lineNumbers; } /** * Retrieves the line number from the specified frame in the stack. * * @param depth The depth of the frame for which to retrieve the line * number. * * @return The line number from the specified frame in the stack. */ public int getLineNumber(int depth) { return lineNumbers[depth]; } /** * Retrieves the hash code for this profile stack. It will be the sum of the * hash codes for the class and method name and line number for the first * frame. * * @return The hash code for this profile stack. */ public int hashCode() { if (numFrames == 0) { return 0; } else { return (classNames[0].hashCode() + methodNames[0].hashCode() + lineNumbers[0]); } } /** * Indicates whether to the provided object is equal to this profile stack. * * @param o The object for which to make the determination. * * @return <CODE>true</CODE> if the provided object is a profile stack object * with the same set of class names, method names, and line numbers * as this profile stack, or <CODE>false</CODE> if not. */ public boolean equals(Object o) { if (o == null) { return false; } else if (this == o) { return true; } try { ProfileStack s = (ProfileStack) o; if (numFrames != s.numFrames) { return false; } for (int i=0; i < numFrames; i++) { if ((lineNumbers[i] != s.lineNumbers[i]) || (! classNames[i].equals(s.classNames[i])) || (! methodNames[i].equals(s.methodNames[i]))) { return false; } } return true; } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } return false; } } /** * Encodes and writes this profile stack to the capture file. * * @param writer The writer to use. * @throws IOException if an error occurs while writing. */ public void write(ASN1Writer writer) throws IOException { writer.writeStartSequence(); writer.writeInteger(numFrames); for (int i=0; i < numFrames; i++) { writer.writeOctetString(classNames[i]); writer.writeOctetString(methodNames[i]); writer.writeInteger(lineNumbers[i]); } writer.writeEndSequence(); } /** * Decodes the contents of the provided element as a profile stack. * * @param reader The ASN.1 reader to read the encoded profile stack * information from. * * @return The decoded profile stack. * @throws ASN1Exception If the element could not be decoded for some reason. * */ public static ProfileStack decode(ASN1Reader reader) throws ASN1Exception { reader.readStartSequence(); int numFrames = (int)reader.readInteger(); String[] classNames = new String[numFrames]; String[] methodNames = new String[numFrames]; int[] lineNumbers = new int[numFrames]; int i = 0; while(reader.hasNextElement()) { classNames[i] = reader.readOctetStringAsString(); methodNames[i] = reader.readOctetStringAsString(); lineNumbers[i] = (int)reader.readInteger(); i++; } reader.readEndSequence(); return new ProfileStack(classNames, methodNames, lineNumbers); } }