[logback-dev] svn commit: r1795 - in logback/trunk: logback-classic logback-classic/src/main/java/ch/qos/logback/classic/pattern logback-classic/src/main/java/ch/qos/logback/classic/spi logback-classic/src/test/java/ch/qos/logback/classic/pattern logback-classic/src/test/java/ch/qos/logback/classic/spi logback-classic/src/test/java/ch/qos/logback/classic/spi/special logback-classic/src/test/java/ch/qos/logback/classic/util logback-core/src/main/java/ch/qos/logback/core/util

noreply.ceki at qos.ch noreply.ceki at qos.ch
Mon Sep 8 17:42:48 CEST 2008


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&uuml;lc&uuml;
+ */
+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);
+  }
+}


More information about the logback-dev mailing list