Coverage Report - org.crosswire.common.util.StackTrace
 
Classes in this File Line Coverage Branch Coverage Complexity
StackTrace
0%
0/65
0%
0/20
2
StackTrace$1
0%
0/4
0%
0/2
2
StackTrace$2
0%
0/4
0%
0/2
2
StackTrace$3
0%
0/4
0%
0/2
2
StackTrace$AbstractStackIterator
0%
0/4
0%
0/2
2
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.common.util;
 21  
 
 22  
 import java.io.PrintWriter;
 23  
 import java.io.StringWriter;
 24  
 import java.util.Iterator;
 25  
 import java.util.NoSuchElementException;
 26  
 
 27  
 /**
 28  
  * Unscramble the current stack, and present the data from it to the user in
 29  
  * various forms. This code is slightly dodgy in that it makes use of the way
 30  
  * exceptions print their stack traces, however it is probably a safe enough
 31  
  * assumption for the moment.
 32  
  * 
 33  
  * @see gnu.lgpl.License The GNU Lesser General Public License for details.
 34  
  * @author Joe Walker
 35  
  */
 36  0
 public final class StackTrace {
 37  
     /**
 38  
      * Generate a stack trace an model it
 39  
      */
 40  0
     public StackTrace() {
 41  0
         init(new Throwable(), 2);
 42  0
     }
 43  
 
 44  
     /**
 45  
      * We already have an Exception that we'd like to model
 46  
      * 
 47  
      * @param ex
 48  
      *            The Exception to model
 49  
      */
 50  0
     public StackTrace(Throwable ex) {
 51  0
         init(ex, 1);
 52  0
     }
 53  
 
 54  
     /**
 55  
      * Create a stack trace of the code at this point
 56  
      * 
 57  
      * @param exception
 58  
      *            The Throwable containing the Stack Trace
 59  
      * @param discard
 60  
      *            The number of uppermost stack frames to ignore
 61  
      */
 62  
     private void init(Throwable exception, int discard) {
 63  0
         StringWriter sout = new StringWriter();
 64  0
         exception.printStackTrace(new PrintWriter(sout));
 65  0
         String msg = new String(sout.getBuffer());
 66  0
         String[] calls = StringUtil.split(msg, "\n\r");
 67  
 
 68  0
         int total = 0;
 69  0
         for (int i = 0; i < calls.length - discard; i++) {
 70  0
             String call = calls[i + discard];
 71  
 
 72  0
             if (!(call.startsWith("Caused") || call.indexOf("...") >= 0)) {
 73  0
                 total++;
 74  
             }
 75  
         }
 76  
 
 77  0
         classNames = new String[total];
 78  0
         methodNames = new String[total];
 79  0
         fileNames = new String[total];
 80  0
         lineNumbers = new int[total];
 81  
 
 82  0
         int j = 0;
 83  0
         for (int i = 0; i < calls.length - discard; i++) {
 84  0
             String call = calls[i + discard];
 85  0
             boolean oops = false;
 86  
             try {
 87  0
                 if (!(call.startsWith("Caused") || call.indexOf("...") >= 0)) {
 88  0
                     int spcIndex = call.indexOf(' ');
 89  0
                     int lhsIndex = call.indexOf('(');
 90  0
                     int clnIndex = call.indexOf(':');
 91  0
                     int rhsIndex = call.indexOf(')');
 92  
 
 93  0
                     String fullFn = call.substring(spcIndex + 1, lhsIndex).trim();
 94  0
                     int lastDot = fullFn.lastIndexOf('.');
 95  
 
 96  0
                     classNames[j] = fullFn.substring(0, lastDot).replace('/', '.');
 97  0
                     methodNames[j] = fullFn.substring(lastDot + 1);
 98  
 
 99  0
                     if (clnIndex != -1 && lhsIndex < clnIndex) {
 100  0
                         fileNames[j] = call.substring(lhsIndex + 1, clnIndex);
 101  0
                         lineNumbers[j] = Integer.parseInt(call.substring(clnIndex + 1, rhsIndex));
 102  
                     } else {
 103  0
                         fileNames[j] = call.substring(lhsIndex + 1, rhsIndex);
 104  0
                         lineNumbers[j] = 0;
 105  
                     }
 106  0
                     j++;
 107  
                 }
 108  0
             } catch (NumberFormatException ex) {
 109  0
                 oops = true;
 110  0
             } catch (StringIndexOutOfBoundsException ex) {
 111  
                 // For whatever reason, Java 7 under Web Start is throwing this on
 112  
                 // call.substring(spcIndex + 1, lhsIndex) with a -56 being passed.
 113  0
                 oops = true;
 114  0
             }
 115  0
             if (oops) {
 116  0
                 classNames[j] = "ParseError: ";
 117  0
                 methodNames[j] = call;
 118  0
                 fileNames[j] = "Error";
 119  0
                 lineNumbers[j] = 0;
 120  0
                 j++;
 121  
             }
 122  
         }
 123  0
     }
 124  
 
 125  
     /**
 126  
      * How many stack elements are there?
 127  
      * 
 128  
      * @return the number of stack elements
 129  
      */
 130  
     public int countStackElements() {
 131  0
         return methodNames.length;
 132  
     }
 133  
 
 134  
     /**
 135  
      * Get the name of a function
 136  
      * 
 137  
      * @param level
 138  
      *            Number of calling function
 139  
      * @return the function name
 140  
      */
 141  
     public String getFunctionName(int level) {
 142  0
         return methodNames[level];
 143  
     }
 144  
 
 145  
     /**
 146  
      * Get the name of a function including class name
 147  
      * 
 148  
      * @param level
 149  
      *            Number of calling function
 150  
      * @return the full function name
 151  
      */
 152  
     public String getFullFunctionName(int level) {
 153  0
         return classNames[level] + '.' + methodNames[level] + "()";
 154  
     }
 155  
 
 156  
     /**
 157  
      * Get the name of a class
 158  
      * 
 159  
      * @param level
 160  
      *            Number of calling function
 161  
      * @return the class name
 162  
      */
 163  
     public String getClassName(int level) {
 164  0
         return classNames[level];
 165  
     }
 166  
 
 167  
     /**
 168  
      * Get the name of a file
 169  
      * 
 170  
      * @param level
 171  
      *            Number of calling function
 172  
      * @return the file name
 173  
      */
 174  
     public String getFileName(int level) {
 175  0
         return fileNames[level];
 176  
     }
 177  
 
 178  
     /**
 179  
      * Get the line number within a file
 180  
      * 
 181  
      * @param level
 182  
      *            Number of calling function
 183  
      * @return the line number
 184  
      */
 185  
     public int getLineNumber(int level) {
 186  0
         return lineNumbers[level];
 187  
     }
 188  
 
 189  
     /**
 190  
      * Get the count of classes
 191  
      * 
 192  
      * @return the number of classes
 193  
      */
 194  
     public int getClassCount() {
 195  0
         return classNames.length;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Get the Class that owns the function
 200  
      * 
 201  
      * @param level
 202  
      *            Number of calling function
 203  
      * @return the function owner
 204  
      */
 205  
     public Class<?> getClass(int level) {
 206  
         try {
 207  0
             return ClassUtil.forName(classNames[level]);
 208  0
         } catch (ClassNotFoundException ex) {
 209  0
             assert false : ex;
 210  0
             return null;
 211  
         }
 212  
     }
 213  
 
 214  
     /**
 215  
      * Base class for the real enumeration implementations below
 216  
      * @param <T> the type of the object in the stack
 217  
      */
 218  0
     public abstract class AbstractStackIterator<T> implements Iterator<T> {
 219  
         /* (non-Javadoc)
 220  
          * @see java.util.Iterator#hasNext()
 221  
          */
 222  
         public boolean hasNext() {
 223  0
             return level < getClassCount();
 224  
         }
 225  
 
 226  
         /* (non-Javadoc)
 227  
          * @see java.util.Iterator#remove()
 228  
          */
 229  
         public void remove() {
 230  0
             throw new UnsupportedOperationException();
 231  
         }
 232  
 
 233  
         /**
 234  
          * @return the level.
 235  
          * @throws NoSuchElementException 
 236  
          */
 237  
         public int getAndIncrementLevel() throws NoSuchElementException {
 238  0
             return level++;
 239  
         }
 240  
 
 241  
         /**
 242  
          * Are there more stack levels
 243  
          */
 244  
         private int level;
 245  
     }
 246  
 
 247  
     /**
 248  
      * To iterate over the class names
 249  
      * 
 250  
      * @return an iterator of class names
 251  
      */
 252  
     public Iterator<String> getClassNameElements() {
 253  0
         return new AbstractStackIterator<String>() {
 254  
             public String next() throws NoSuchElementException {
 255  0
                 if (!hasNext()) {
 256  0
                     throw new NoSuchElementException();
 257  
                 }
 258  0
                 return getClassName(getAndIncrementLevel());
 259  
             }
 260  
         };
 261  
     }
 262  
 
 263  
     /**
 264  
      * To iterate over the function names
 265  
      * 
 266  
      * @return an iterator of function names
 267  
      */
 268  
     public Iterator<String> getFunctionNameElements() {
 269  0
         return new AbstractStackIterator<String>() {
 270  
             public String next() throws NoSuchElementException {
 271  0
                 if (!hasNext()) {
 272  0
                     throw new NoSuchElementException();
 273  
                 }
 274  0
                 return getFunctionName(getAndIncrementLevel());
 275  
             }
 276  
         };
 277  
     }
 278  
 
 279  
     /**
 280  
      * To iterate over the full function names
 281  
      * 
 282  
      * @return an iterator of full function names
 283  
      */
 284  
     public Iterator<String> getFullFunctionNameElements() {
 285  0
         return new AbstractStackIterator<String>() {
 286  
             public String next() throws NoSuchElementException {
 287  0
                 if (!hasNext()) {
 288  0
                     throw new NoSuchElementException();
 289  
                 }
 290  0
                 return getFullFunctionName(getAndIncrementLevel());
 291  
             }
 292  
         };
 293  
     }
 294  
 
 295  
     /**
 296  
      * Array containing the class names
 297  
      */
 298  
     private String[] classNames;
 299  
 
 300  
     /**
 301  
      * Array containing the method names
 302  
      */
 303  
     private String[] methodNames;
 304  
 
 305  
     /**
 306  
      * Array containing the file names
 307  
      */
 308  
     private String[] fileNames;
 309  
 
 310  
     /**
 311  
      * Array containing the line numbers
 312  
      */
 313  
     private int[] lineNumbers;
 314  
 }