
Author: ceki Date: Mon Sep 8 17:42:48 2008 New Revision: 1795 Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingData.java - copied, changed from r1794, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/PackageInfo.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingDataCalculator.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/BasicCPDCTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/CPDCSpecial.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/LocalFirstClassLoader.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/special/ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/special/CPDCSpecialImpl.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/util/TeztHelper.java logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/SystemInfo.java Removed: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/PackageInfo.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/PackageInfoCalculator.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageInfoTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageVersionCalculatorTest.java Modified: logback/trunk/logback-classic/pom.xml logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ExtendedThrowableProxyConverter.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/StackTraceElementProxy.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxy.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ThrowableProxyConverterTest.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageTest.java Log: LBGENERAL-23 This code attempts to guarantee that the extracted class packaging information is extracting using the *exact* same classloader was used to load a given class in the stack frame. Associated test cases. Modified: logback/trunk/logback-classic/pom.xml ============================================================================== --- logback/trunk/logback-classic/pom.xml (original) +++ logback/trunk/logback-classic/pom.xml Mon Sep 8 17:42:48 2008 @@ -114,7 +114,6 @@ <scope>test</scope> </dependency> - </dependencies> <build> @@ -159,9 +158,9 @@ </excludes> </configuration> </plugin> - </plugins> + </build> </project> \ No newline at end of file Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ExtendedThrowableProxyConverter.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ExtendedThrowableProxyConverter.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ExtendedThrowableProxyConverter.java Mon Sep 8 17:42:48 2008 @@ -9,7 +9,7 @@ */ package ch.qos.logback.classic.pattern; -import ch.qos.logback.classic.spi.PackageInfo; +import ch.qos.logback.classic.spi.ClassPackagingData; import ch.qos.logback.classic.spi.StackTraceElementProxy; import ch.qos.logback.classic.spi.ThrowableDataPoint; @@ -20,9 +20,9 @@ protected void extraData(StringBuilder builder, ThrowableDataPoint tdp) { StackTraceElementProxy step = tdp.getStackTraceElementProxy(); if(step != null) { - PackageInfo pi = step.getPackageInfo(); + ClassPackagingData pi = step.getClassPackagingData(); if(pi != null) { - builder.append(" [").append(pi.getJarName()).append(':').append(pi.getVersion()).append(']'); + builder.append(" [").append(pi.getCodeLocation()).append(':').append(pi.getVersion()).append(']'); } } } Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java Mon Sep 8 17:42:48 2008 @@ -14,7 +14,7 @@ import org.slf4j.Marker; -import ch.qos.logback.classic.spi.PackageInfo; +import ch.qos.logback.classic.spi.ClassPackagingData; /** * @@ -22,7 +22,7 @@ */ public class Util { - static Map<String, PackageInfo> cache = new HashMap<String, PackageInfo>(); + static Map<String, ClassPackagingData> cache = new HashMap<String, ClassPackagingData>(); static public boolean match(Marker marker, Marker[] markerArray) { if (markerArray == null) { Copied: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingData.java (from r1794, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/PackageInfo.java) ============================================================================== --- /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/PackageInfo.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingData.java Mon Sep 8 17:42:48 2008 @@ -11,24 +11,36 @@ import java.io.Serializable; -public class PackageInfo implements Serializable { +public class ClassPackagingData implements Serializable { private static final long serialVersionUID = 637783570208674312L; - String jarName; - String version; + final String codeLocation; + final String version; + private final boolean exact; - public PackageInfo(String jarName, String version) { - this.jarName = jarName; + public ClassPackagingData(String codeLocation, String version) { + this.codeLocation = codeLocation; this.version = version; + this.exact = true; } - public String getJarName() { - return jarName; + public ClassPackagingData(String classLocation, String version, boolean exact) { + this.codeLocation = classLocation; + this.version = version; + this.exact = exact; + } + + public String getCodeLocation() { + return codeLocation; } public String getVersion() { return version; } + + public boolean isExact() { + return exact; + } } Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingDataCalculator.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ClassPackagingDataCalculator.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,245 @@ +/** + * Logback: the generic, reliable, fast and flexible logging framework. + * + * Copyright (C) 2000-2008, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ +package ch.qos.logback.classic.spi; + +import java.net.URL; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import sun.reflect.Reflection; +import ch.qos.logback.classic.spi.ThrowableDataPoint.ThrowableDataPointType; + +/** + * + * Given a classname locate associated PackageInfo (jar name, version name). + * + * @author James Strachan + * @Ceki Gülcü + */ +public class ClassPackagingDataCalculator { + + final static StackTraceElementProxy[] STEP_ARRAY_TEMPLATE = new StackTraceElementProxy[0]; + + HashMap<String, ClassPackagingData> cache = new HashMap<String, ClassPackagingData>(); + + public ClassPackagingDataCalculator() { + } + + public void calculate(ThrowableDataPoint[] tdpArray) { + int steStart = 0; + StackTraceElementProxy[] stepArray = new StackTraceElementProxy[0]; + do { + steStart = findSTEStartIndex(tdpArray, steStart+stepArray.length); + stepArray = getSTEPArray(tdpArray, steStart); + populateFrames(stepArray); + } while(steStart != -1); + } + + void populateFrames(StackTraceElementProxy[] stepArray) { + // in the initial part of this method we populate package informnation for + // common stack frames + Throwable t = new Throwable("local stack reference"); + StackTraceElement[] localteSTEArray = t.getStackTrace(); + int commonFrames = STEUtil.findNumberOfCommonFrames(localteSTEArray, + stepArray); + int localFirstCommon = localteSTEArray.length - commonFrames; + int stepFirstCommon = stepArray.length - commonFrames; + + ClassLoader lastExactClassLoader = null; + ClassLoader firsExactClassLoader = null; + + int missfireCount = 0; + for (int i = 0; i < commonFrames; i++) { + Class callerClass = Reflection.getCallerClass(localFirstCommon + i + - missfireCount + 1); + StackTraceElementProxy step = stepArray[stepFirstCommon + i]; + String stepClassname = step.ste.getClassName(); + + if (stepClassname.equals(callerClass.getName())) { + lastExactClassLoader = callerClass.getClassLoader(); + if(firsExactClassLoader == null) { + firsExactClassLoader = callerClass.getClassLoader(); + } + ClassPackagingData pi = calculateByExactType(callerClass); + step.setPackageInfo(pi); + } else { + missfireCount++; + ClassPackagingData pi = computeBySTEP(step, lastExactClassLoader); + step.setPackageInfo(pi); + } + } + populateUncommonFrames(commonFrames, stepArray, firsExactClassLoader); + } + + int findSTEStartIndex(ThrowableDataPoint[] tdpArray, int from) { + int len = tdpArray.length; + if (from < 0 || from >= len) { + return -1; + } + for (int i = from; i < len; i++) { + if (tdpArray[i].type == ThrowableDataPointType.STEP) { + return i; + } + } + return -1; + } + + private StackTraceElementProxy[] getSTEPArray(ThrowableDataPoint[] tdpArray, int from) { + List<StackTraceElementProxy> stepList = new LinkedList<StackTraceElementProxy>(); + int len = tdpArray.length; + if (from < 0 || from >= len) { + return stepList.toArray(STEP_ARRAY_TEMPLATE); + } + for (int i = from; i < len; i++) { + final ThrowableDataPoint tdp = tdpArray[i]; + + if (tdp.type == ThrowableDataPointType.STEP) { + stepList.add(tdp.getStackTraceElementProxy()); + } else { + break; + } + } + return stepList.toArray(STEP_ARRAY_TEMPLATE); + } + + void populateUncommonFrames(int commonFrames, StackTraceElementProxy[] stepArray, ClassLoader firstExactClassLoader) { + int uncommonFrames = stepArray.length-commonFrames; + for (int i = 0; i < uncommonFrames; i++) { + StackTraceElementProxy step = stepArray[i]; + ClassPackagingData pi = computeBySTEP(step, firstExactClassLoader); + step.setPackageInfo(pi); + } + } + + private ClassPackagingData calculateByExactType(Class type) { + String className = type.getName(); + ClassPackagingData cpd = cache.get(className); + if (cpd != null) { + return cpd; + } + String version = getImplementationVersion(type); + String codeLocation = getCodeLocation(type); + cpd = new ClassPackagingData(codeLocation, version); + cache.put(className, cpd); + return cpd; + } + + private ClassPackagingData computeBySTEP(StackTraceElementProxy step, ClassLoader lastExactClassLoader) { + String className = step.ste.getClassName(); + ClassPackagingData cpd = cache.get(className); + if (cpd != null) { + return cpd; + } + Class type = bestEffortLoadClass(lastExactClassLoader, className); + String version = getImplementationVersion(type); + String codeLocation = getCodeLocation(type); + cpd = new ClassPackagingData(codeLocation, version, false); + cache.put(className, cpd); + return cpd; + } + + + String getImplementationVersion(Class type) { + Package aPackage = type.getPackage(); + if (aPackage != null) { + String v = aPackage.getImplementationVersion(); + if (v == null) { + return "na"; + } else { + return v; + } + } + return "na"; + + } + + String getCodeLocation(Class type) { + try { + if (type != null) { + // file:/C:/java/maven-2.0.8/repo/com/icegreen/greenmail/1.3/greenmail-1.3.jar + URL resource = type.getProtectionDomain().getCodeSource().getLocation(); + if (resource != null) { + String locationStr = resource.toString(); + // now lets remove all but the file name + String result = getCodeLocation(locationStr, '/'); + if(result != null) { + return result; + } + return getCodeLocation(locationStr, '\\'); + } + } + } catch (Exception e) { + // ignore + } + return "na"; + } + + + private String getCodeLocation(String locationStr, char separator) { + int idx = locationStr.lastIndexOf(separator); + if(isFolder(idx, locationStr)) { + idx = locationStr.lastIndexOf(separator, idx-1); + return locationStr.substring(idx+1); + } else if (idx > 0) { + return locationStr.substring(idx + 1); + } + return null; + } + + private boolean isFolder(int idx, String text) { + return (idx != -1 && idx+1 == text.length()); + } + + private Class loadClass(ClassLoader cl, String className) { + if(cl == null) { + return null; + } + try { + return cl.loadClass(className); + } catch (ClassNotFoundException e1) { + return null; + } catch(Exception e) { + e.printStackTrace(); // this is unexpected + return null; + } + + } + + /** + * + * @param lastGuaranteedClassLoader may be null + * @param className + * @return + */ + private Class bestEffortLoadClass(ClassLoader lastGuaranteedClassLoader, String className) { + Class result = loadClass(lastGuaranteedClassLoader, className); + if(result != null) { + return result; + } + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + if(tccl != lastGuaranteedClassLoader) { + result = loadClass(tccl, className); + } + if(result != null) { + return result; + } + + try { + return Class.forName(className); + } catch (ClassNotFoundException e1) { + return null; + } catch(Exception e) { + e.printStackTrace(); // this is unexpected + return null; + } + } + +} Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/StackTraceElementProxy.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/StackTraceElementProxy.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/StackTraceElementProxy.java Mon Sep 8 17:42:48 2008 @@ -10,7 +10,7 @@ final StackTraceElement ste; private String steAsString; - private PackageInfo pi; + private ClassPackagingData cpd; StackTraceElementProxy(StackTraceElement ste) { if(ste == null) { @@ -26,12 +26,12 @@ return steAsString; } - void setPackageInfo(PackageInfo pi) { - this.pi = pi; + void setPackageInfo(ClassPackagingData cpd) { + this.cpd = cpd; } - public PackageInfo getPackageInfo() { - return pi; + public ClassPackagingData getClassPackagingData() { + return cpd; } @Override Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxy.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxy.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/ThrowableProxy.java Mon Sep 8 17:42:48 2008 @@ -11,32 +11,32 @@ import java.util.Arrays; +import ch.qos.logback.core.CoreGlobal; public class ThrowableProxy implements java.io.Serializable { private static final long serialVersionUID = 6307784764626694851L; private ThrowableDataPoint[] tdpArray; private transient final Throwable throwable; - private transient PackageInfoCalculator packageInfoCalculator; + private transient ClassPackagingDataCalculator classPackagingDataCalculator; public ThrowableProxy(Throwable throwable) { this.throwable = throwable; - this.tdpArray = ThrowableToDataPointArray.convert(throwable); + this.tdpArray = ThrowableToDataPointArray.convert(throwable); } public Throwable getThrowable() { return throwable; } - - - public PackageInfoCalculator getPackageInfoCalculator() { - // if original instance (non-deserialized), and packageInfoCalculator + + public ClassPackagingDataCalculator getClassPackagingDataCalculator() { + // if original instance (non-deserialized), and classPackagingDataCalculator // is not already initialized, then create an instance - // here we assume that (throwable == null) for deserialized instances - if(throwable != null && packageInfoCalculator == null) { - packageInfoCalculator = new PackageInfoCalculator(); + // here we assume that (throwable == null) for deserialized instances + if (throwable != null && classPackagingDataCalculator == null) { + classPackagingDataCalculator = new ClassPackagingDataCalculator(); } - return packageInfoCalculator; + return classPackagingDataCalculator; } /** @@ -67,5 +67,31 @@ return false; return true; } - + + public void fullDump() { + StringBuilder builder = new StringBuilder(); + for (ThrowableDataPoint tdp : getThrowableDataPointArray()) { + String string = tdp.toString(); + builder.append(string); + extraData(builder, tdp); + builder.append(CoreGlobal.LINE_SEPARATOR); + } + System.out.println(builder.toString()); + } + + protected void extraData(StringBuilder builder, ThrowableDataPoint tdp) { + StackTraceElementProxy step = tdp.getStackTraceElementProxy(); + if (step != null) { + ClassPackagingData cpd = step.getClassPackagingData(); + if (cpd != null) { + if(!cpd.isExact()){ + builder.append(" ~[") ; + } else { + builder.append(" [") ; + } + builder.append(cpd.getCodeLocation()).append(':').append( + cpd.getVersion()).append(']'); + } + } + } } Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ThrowableProxyConverterTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ThrowableProxyConverterTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ThrowableProxyConverterTest.java Mon Sep 8 17:42:48 2008 @@ -12,6 +12,7 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.classic.util.TeztHelper; public class ThrowableProxyConverterTest { @@ -45,7 +46,7 @@ @Test public void nested() { - Throwable t = makeNestedException(1); + Throwable t = TeztHelper.makeNestedException(1); verify(t); } @@ -59,11 +60,5 @@ assertEquals(sw.toString(), result); } - Throwable makeNestedException(int level) { - if (level == 0) { - return new Exception("nesting level=" + level); - } - Throwable cause = makeNestedException(level - 1); - return new Exception("nesting level =" + level, cause); - } + } Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/BasicCPDCTest.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/BasicCPDCTest.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,95 @@ +package ch.qos.logback.classic.spi; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import ch.qos.logback.classic.util.TeztHelper; +import ch.qos.logback.core.util.SystemInfo; + +public class BasicCPDCTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + public void verify(ThrowableDataPoint[] tdpArray) { + for (ThrowableDataPoint tdp : tdpArray) { + StackTraceElementProxy step = tdp.getStackTraceElementProxy(); + if (step != null) { + assertNotNull(step.getClassPackagingData()); + } + } + } + + @Test public void otherJD() { + System.out.println(SystemInfo.getJavaVendor()); + } + + @Test + public void smoke() throws Exception { + Throwable t = new Throwable("x"); + ThrowableProxy tp = new ThrowableProxy(t); + ClassPackagingDataCalculator cpdc = tp.getClassPackagingDataCalculator(); + ThrowableDataPoint[] tdpArray = tp.getThrowableDataPointArray(); + cpdc.calculate(tdpArray); + verify(tdpArray); + } + + @Test + public void nested() throws Exception { + Throwable t = TeztHelper.makeNestedException(3); + ThrowableProxy tp = new ThrowableProxy(t); + ClassPackagingDataCalculator cpdc = tp.getClassPackagingDataCalculator(); + ThrowableDataPoint[] tdpArray = tp.getThrowableDataPointArray(); + cpdc.calculate(tdpArray); + verify(tdpArray); + } + + public void doCalculateClassPackagingData( + boolean withClassPackagingCalculation) { + try { + throw new Exception("testing"); + } catch (Throwable e) { + ThrowableProxy tp = new ThrowableProxy(e); + if (withClassPackagingCalculation) { + tp.getClassPackagingDataCalculator(); + ClassPackagingDataCalculator cpdc = tp + .getClassPackagingDataCalculator(); + ThrowableDataPoint[] tdpArray = tp.getThrowableDataPointArray(); + cpdc.calculate(tdpArray); + } + } + } + + double loop(int len, boolean withClassPackagingCalculation) { + long start = System.nanoTime(); + for (int i = 0; i < len; i++) { + doCalculateClassPackagingData(withClassPackagingCalculation); + } + return (1.0 * System.nanoTime() - start) / len / 1000; + } + + @Test + public void perfTest() { + int len = 500; + loop(len, false); + loop(len, true); + + double d0 = loop(len, false); + System.out.println("without packaging info " + d0 + " microseconds"); + + double d1 = loop(len, true); + System.out.println("with packaging info " + d1 + " microseconds"); + assertTrue("computing class packaging data (" + d1 + + ") should have been less than six times the time it takes to process an exception" + (d0 * 6), + d0 * 6 > d1); + } +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/CPDCSpecial.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/CPDCSpecial.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,11 @@ +package ch.qos.logback.classic.spi; + +public interface CPDCSpecial { + + public abstract void doTest(); + + public abstract Throwable getThrowable(); + + public abstract ThrowableProxy getThrowableProxy(); + +} \ No newline at end of file Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/LocalFirstClassLoader.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/LocalFirstClassLoader.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,66 @@ +package ch.qos.logback.classic.spi; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * An almost trivial no fuss implementation of a class loader following the + * child-first delegation model. + * + * @author Ceki G�lc� + */ +public class LocalFirstClassLoader extends URLClassLoader { + + public LocalFirstClassLoader(URL[] urls) { + super(urls); + } + + public LocalFirstClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public void addURL(URL url) { + super.addURL(url); + } + + public Class<?> loadClass(String name) throws ClassNotFoundException { + return loadClass(name, false); + } + + /** + * We override the parent-first behavior established by java.lang.Classloader. + * + * The implementation is surprisingly straightforward. + */ + protected Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException { + + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + + // if not loaded, search the local (child) resources + if (c == null) { + try { + c = findClass(name); + } catch (ClassNotFoundException cnfe) { + // ignore + } + } + + // if we could not find it, delegate to parent + // Note that we don't attempt to catch any ClassNotFoundException + if (c == null) { + if (getParent() != null) { + c = getParent().loadClass(name); + } else { + c = getSystemClassLoader().loadClass(name); + } + } + + if (resolve) { + resolveClass(c); + } + + return c; + } +} Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/PackageTest.java Mon Sep 8 17:42:48 2008 @@ -24,6 +24,7 @@ suite.addTest(new JUnit4TestAdapter (LoggerComparatorTest.class)); suite.addTest(new JUnit4TestAdapter (LoggingEventSerializationTest.class)); suite.addTest(new JUnit4TestAdapter(ch.qos.logback.classic.spi.ThrowableToDataPointTest.class)); + suite.addTest(new JUnit4TestAdapter(ch.qos.logback.classic.spi.BasicCPDCTest.class)); return suite; } } \ No newline at end of file Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/special/CPDCSpecialImpl.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/spi/special/CPDCSpecialImpl.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,31 @@ +package ch.qos.logback.classic.spi.special; + +import ch.qos.logback.classic.spi.CPDCSpecial; +import ch.qos.logback.classic.spi.ClassPackagingDataCalculator; +import ch.qos.logback.classic.spi.ThrowableProxy; + + +public class CPDCSpecialImpl implements CPDCSpecial { + + + Throwable throwable; + ThrowableProxy throwableProxy; + + public void doTest() { + nesting(); + } + + private void nesting() { + throwable = new Throwable("x"); + throwableProxy = new ThrowableProxy(throwable); + ClassPackagingDataCalculator cpdc = new ClassPackagingDataCalculator(); + cpdc.calculate(throwableProxy.getThrowableDataPointArray()); + } + + public Throwable getThrowable() { + return throwable; + } + public ThrowableProxy getThrowableProxy() { + return throwableProxy; + } +} Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/util/TeztHelper.java ============================================================================== --- (empty file) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/util/TeztHelper.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,13 @@ +package ch.qos.logback.classic.util; + +public class TeztHelper { + + + static public Throwable makeNestedException(int level) { + if (level == 0) { + return new Exception("nesting level=" + level); + } + Throwable cause = makeNestedException(level - 1); + return new Exception("nesting level =" + level, cause); + } +} Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/SystemInfo.java ============================================================================== --- (empty file) +++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/SystemInfo.java Mon Sep 8 17:42:48 2008 @@ -0,0 +1,9 @@ +package ch.qos.logback.core.util; + +public class SystemInfo { + + + public static String getJavaVendor() { + return OptionHelper.getSystemProperty("java.vendor", null); + } +}