001    /* StackTraceElement.java -- One function call or call stack element
002       Copyright (C) 2001, 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.lang;
040    
041    import java.io.Serializable;
042    
043    /**
044     * One function call or stack trace element. Gives information about
045     * the execution point such as the source file name, the line number,
046     * the fully qualified class name, the method name and whether this method
047     * is native, if this information is known.
048     *
049     * @author Mark Wielaard (mark@klomp.org)
050     * @author Eric Blake (ebb9@email.byu.edu)
051     * @since 1.4
052     * @status updated to 1.5
053     */
054    public final class StackTraceElement implements Serializable
055    {
056      /**
057       * Compatible with JDK 1.4+.
058       */
059      private static final long serialVersionUID = 6992337162326171013L;
060    
061      /**
062       * The name of the file, null if unknown.
063       *
064       * @serial the source code filename, if known
065       */
066      private final String fileName;
067    
068      /**
069       * The line number in the file, negative if unknown.
070       *
071       * @serial the source code line number, if known
072       */
073      private final int lineNumber;
074    
075      /**
076       * The fully qualified class name, null if unknown.
077       *
078       * @serial the enclosing class, if known
079       */
080      private final String declaringClass;
081    
082      /**
083       * The method name in the class, null if unknown.
084       *
085       * @serial the enclosing method, if known
086       */
087      private final String methodName;
088    
089      /** Whether the method is native. */
090      private final transient boolean isNative;
091    
092      /**
093       * A package local constructor for the StackTraceElement class, to be
094       * called by the Virtual Machine as part of Throwable.fillInStackTrace.
095       * There are no public constructors defined for this class. Creation
096       * of new elements is implementation specific.
097       *
098       * @param fileName the name of the file, null if unknown
099       * @param lineNumber the line in the file, negative if unknown
100       * @param className the fully qualified name of the class, null if unknown
101       * @param methodName the name of the method, null if unknown
102       * @param isNative true if native, false otherwise
103       */
104      StackTraceElement(String fileName, int lineNumber, String className,
105                        String methodName, boolean isNative)
106      {
107        this.fileName = fileName;
108        this.lineNumber = lineNumber;
109        this.declaringClass = className;
110        this.methodName = methodName;
111        this.isNative = isNative;
112      }
113    
114      /**
115       * Create a new StackTraceElement representing a given source location.
116       *
117       * @param className the fully qualified name of the class
118       * @param methodName the name of the method
119       * @param fileName the name of the file, null if unknown
120       * @param lineNumber the line in the file, negative if unknown, or -2
121       * if this method is native
122       * 
123       * @since 1.5
124       */
125      public StackTraceElement(String className, String methodName, String fileName,
126                               int lineNumber)
127      {
128        this(fileName, lineNumber, className, methodName, lineNumber == -2);
129        // The public constructor doesn't allow certain values to be null.
130        if (className == null || methodName == null)
131          throw new NullPointerException("invalid argument to constructor");
132      }
133    
134      /**
135       * Returns the name of the file, or null if unknown. This is usually
136       * obtained from the <code>SourceFile</code> attribute of the class file
137       * format, if present.
138       *
139       * @return the file name
140       */
141      public String getFileName()
142      {
143        return fileName;
144      }
145    
146      /**
147       * Returns the line number in the file, or a negative number if unknown.
148       * This is usually obtained from the <code>LineNumberTable</code> attribute
149       * of the method in the class file format, if present.
150       *
151       * @return the line number
152       */
153      public int getLineNumber()
154      {
155        return lineNumber;
156      }
157    
158      /**
159       * Returns the fully qualified class name, or null if unknown.
160       *
161       * @return the class name
162       */
163      public String getClassName()
164      {
165        return declaringClass;
166      }
167    
168      /**
169       * Returns the method name in the class, or null if unknown. If the
170       * execution point is in a constructor, the name is
171       * <code>&lt;init&gt;</code>; if the execution point is in the class
172       * initializer, the name is <code>&lt;clinit&gt;</code>.
173       *
174       * @return the method name
175       */
176      public String getMethodName()
177      {
178        return methodName;
179      }
180    
181      /**
182       * Returns true if the method is native, or false if it is not or unknown.
183       *
184       * @return whether the method is native
185       */
186      public boolean isNativeMethod()
187      {
188        return isNative;
189      }
190    
191      /**
192       * Returns a string representation of this stack trace element. The
193       * returned String is implementation specific. This implementation
194       * returns the following String: "[class][.][method]([file][:line])".
195       * If the fully qualified class name or the method is unknown it is
196       * omitted including the point seperator. If the source file name is
197       * unknown it is replaced by "Unknown Source" if the method is not native
198       * or by "Native Method" if the method is native. If the line number
199       * is unknown it and the colon are omitted.
200       *
201       * @return a string representation of this execution point
202       */
203      public String toString()
204      {
205        StringBuilder sb = new StringBuilder();
206        if (declaringClass != null)
207          {
208            sb.append(declaringClass);
209            if (methodName != null)
210              sb.append('.');
211          }
212        if (methodName != null)
213          sb.append(methodName);
214        sb.append("(");
215        if (fileName != null)
216          sb.append(fileName);
217        else
218          sb.append(isNative ? "Native Method" : "Unknown Source");
219        if (lineNumber >= 0)
220          sb.append(':').append(lineNumber);
221        sb.append(')');
222        return sb.toString();
223      }
224    
225      /**
226       * Returns true if the given object is also a StackTraceElement and all
227       * attributes, except the native flag, are equal (either the same attribute
228       * between the two elments are null, or both satisfy Object.equals).
229       *
230       * @param o the object to compare
231       * @return true if the two are equal
232       */
233      public boolean equals(Object o)
234      {
235        if (! (o instanceof StackTraceElement))
236          return false;
237        StackTraceElement e = (StackTraceElement) o;
238        return equals(fileName, e.fileName)
239          && lineNumber == e.lineNumber
240          && equals(declaringClass, e.declaringClass)
241          && equals(methodName, e.methodName);
242      }
243    
244      /**
245       * Returns the hashCode of this StackTraceElement. This implementation
246       * computes the hashcode by xor-ing the hashcode of all attributes except
247       * the native flag.
248       *
249       * @return the hashcode
250       */
251      public int hashCode()
252      {
253        return hashCode(fileName) ^ lineNumber ^ hashCode(declaringClass)
254          ^ hashCode(methodName);
255      }
256    
257      /**
258       * Compare two objects according to Collection semantics.
259       *
260       * @param o1 the first object
261       * @param o2 the second object
262       * @return o1 == null ? o2 == null : o1.equals(o2)
263       */
264      private static boolean equals(Object o1, Object o2)
265      {
266        return o1 == null ? o2 == null : o1.equals(o2);
267      }
268    
269      /**
270       * Hash an object according to Collection semantics.
271       *
272       * @param o the object to hash
273       * @return o1 == null ? 0 : o1.hashCode()
274       */
275      private static int hashCode(Object o)
276      {
277        return o == null ? 0 : o.hashCode();
278      }
279    }