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