/*
* WOExceptionParser.java
* (c) Copyright 2001 Apple Computer, Inc. All rights reserved.
* This a modified version.
* Original license: http://www.opensource.apple.com/apsl/
*/
package com.webobjects.woextensions;
/**
* WOExceptionParser parse the stack trace of a Java exception (in fact the parse is really
* made in WOParsedErrorLine).
*
* The stack trace is set in an NSArray that will be used in the UI in the exception page.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import com.webobjects.appserver.WOApplication;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSBundle;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSLog;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSPropertyListSerialization;
public class WOExceptionParser {
protected NSMutableArray _stackTrace;
protected Throwable _exception;
protected String _message;
protected String _typeException;
public WOExceptionParser(Throwable exception) {
super();
_stackTrace = new NSMutableArray();
_exception = NSForwardException._originalThrowable(exception);
_message = _exception.getMessage();
_typeException = _exception.getClass().getName();
_parseException();
}
protected NSArray _ignoredPackages() {
NSBundle bundle;
String path, content;
NSDictionary dic = null;
NSMutableArray<NSBundle> allBundles = new NSMutableArray<>(NSBundle.frameworkBundles());
NSMutableArray<String> ignored = new NSMutableArray<>();
for (Enumeration enumerator = allBundles.objectEnumerator(); enumerator.hasMoreElements(); ) {
bundle = (NSBundle) enumerator.nextElement();
path = WOApplication.application().resourceManager().pathForResourceNamed("WOIgnoredPackage.plist",bundle.name(),null);
if (path != null) {
content = _stringFromFileSafely(path);
if (content != null) {
dic = (NSDictionary) NSPropertyListSerialization.propertyListFromString(content);
if (dic != null && dic.containsKey("ignoredPackages")) {
@SuppressWarnings("unchecked")
NSArray<String> tmpArray = (NSArray<String>) dic.objectForKey("ignoredPackages");
if (tmpArray != null && tmpArray.count() > 0) {
ignored.addObjectsFromArray(tmpArray);
}
}
}
}
}
System.out.println("_ignoredPackages:: "+ignored);
return ignored;
}
protected void _verifyPackageForLine(WOParsedErrorLine line, NSArray packages) {
Enumeration enumerator;
String ignoredPackageName, linePackageName;
linePackageName = line.packageName();
enumerator = packages.objectEnumerator();
while (enumerator.hasMoreElements()) {
ignoredPackageName = (String) enumerator.nextElement();
if (linePackageName.startsWith(ignoredPackageName)) {
line.setIgnorePackage(true);
break;
}
}
}
protected void _parseException() {
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter, false);
String string;
NSArray lines;
NSArray ignoredPackage;
WOParsedErrorLine aLine;
String line;
int i, size;
try {
_exception.printStackTrace(pWriter);
pWriter.close();
sWriter.close(); // Added the try/catch as this throws in JDK 1.2 aB.
string = sWriter.toString();
i = _exception.toString().length(); // We skip the name of the exception and the message for our parse
if(string.length() > i+2) { // certain errors don't contain a stack trace
string = string.substring(i+2); // Skip the exception type and message
lines = NSArray.componentsSeparatedByString(string, "\n");
ignoredPackage = _ignoredPackages();
size = lines.count();
_stackTrace = new NSMutableArray(size);
for (i = 0; i < size; i++) {
line = ((String) lines.objectAtIndex(i)).trim();
if (line.startsWith("at ")) {
// If we don't have an open parenthesis it means that we
// have probably reach the latest stack trace.
aLine = new WOParsedErrorLine(line);
_verifyPackageForLine(aLine, ignoredPackage);
_stackTrace.addObject(aLine);
}
}
}
} catch (Throwable e) {
NSLog.err.appendln("WOExceptionParser - exception collecting backtrace data " + e + " - Empty backtrace.");
NSLog.err.appendln(e);
}
if (_stackTrace == null) {
_stackTrace = new NSMutableArray();
}
}
public NSArray stackTrace() {
return _stackTrace;
}
public String typeException() { return _typeException; }
public String message() { return _message; }
/**
* Return a string from the contents of a file, returning null
* instead of any possible exception.
*
* TODO I wonder if this has been done somewhere else in the
* frameworks....
*/
private static String _stringFromFileSafely(String path) {
File f = new File(path);
if (!f.exists()) { return null; }
FileInputStream fis = null;
byte[] data = null;
int bytesRead = 0;
try {
int size = (int) f.length();
fis = new FileInputStream(f);
data = new byte[size];
while (bytesRead < size) {
bytesRead += fis.read(data, bytesRead, size - bytesRead);
}
} catch (java.io.IOException e) {
return null;
} finally {
if (fis != null) {
try {
fis.close();
} catch (java.io.IOException e) {
if (NSLog.debugLoggingAllowedForLevelAndGroups(NSLog.DebugLevelInformational, NSLog.DebugGroupIO)) {
NSLog.debug.appendln("Exception while closing file input stream: " + e.getMessage());
NSLog.debug.appendln(e);
}
}
}
}
if (bytesRead == 0)
return null;
return new String(data);
}
/**
* Return a string for a file, or return an exception.
*/
// TODO Are any sub-classes using this? Do they catch exceptions?
protected static String _stringFromFile(String path) {
File f = new File(path);
FileInputStream fis = null;
byte[] data = null;
if (!f.exists()) {
return null;
}
try {
int size = (int) f.length();
fis = new FileInputStream(f);
data = new byte[size];
int bytesRead = 0;
while (bytesRead < size) {
bytesRead += fis.read(data, bytesRead, size - bytesRead);
}
} catch (IOException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
if (NSLog.debugLoggingAllowedForLevelAndGroups(NSLog.DebugLevelInformational, NSLog.DebugGroupIO)) {
NSLog.debug.appendln("Exception while closing file input stream: " + e.getMessage());
NSLog.debug.appendln(e);
}
}
}
}
return new String(data);
}
}