/** * Copyright (C) 2008-2010, Squale Project - http://www.squale.org * * This file is part of Squale. * * Squale 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, either version 3 of the * License, or any later version. * * Squale is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squale. If not, see <http://www.gnu.org/licenses/>. */ package org.squale.welcom.outils.jdbc; import java.io.PrintWriter; import java.io.StringWriter; /** * Recuperation de LocationInfo de log4j */ public class LocationInfo implements java.io.Serializable { /** * */ private static final long serialVersionUID = 6111845511791831389L; /** Ligne sp�rator */ public final static String LINE_SEP = System.getProperty( "line.separator" ); /** longeur du line separator */ public final static int LINE_SEP_LEN = LINE_SEP.length(); /** * Caller's line number. */ protected transient String lineNumber; /** * Caller's file name. */ protected transient String fileName; /** * Caller's fully qualified class name. */ protected transient String className; /** * Caller's method name. */ protected transient String methodName; /** * All available caller information, in the format * <code>fully.qualified.classname.of.caller.methodName(Filename.java:line)</code> */ private String fullInfo; /** writer */ private static StringWriter sw = new StringWriter(); /** writer */ private static PrintWriter pw = new PrintWriter( sw ); /** * When location information is not available the constant <code>NA</code> is returned. Current value of this * string constant is <b>?</b>. */ public final static String NA = "?"; /** * Instantiate location information based on a Throwable. We expect the Throwable <code>t</code>, to be in the * format * * <pre> * java.lang.Throwable * ... * at org.apache.log4j.PatternLayout.format(PatternLayout.java:413) * at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183) * at org.apache.log4j.Category.callAppenders(Category.java:131) * at org.apache.log4j.Category.log(Category.java:512) * at callers.fully.qualified.className.methodName(FileName.java:74) * ... * </pre> * * <p> * However, we can also deal with JIT compilers that "lose" the location information, especially between the * parentheses. * * @param t le Throwable * @param fqnOfCallingClass la classe sur la quelle on veux l'info */ public LocationInfo( final Throwable t, final String fqnOfCallingClass ) { if ( t == null ) { return; } String s; // Protect against multiple access to sw. synchronized ( sw ) { t.printStackTrace( pw ); s = sw.toString(); sw.getBuffer().setLength( 0 ); } int ibegin, iend; // Given the current structure of the package, the line // containing "org.apache.log4j.Category." should be printed just // before the caller. // This method of searching may not be fastest but it's safer // than counting the stack depth which is not guaranteed to be // constant across JVM implementations. ibegin = s.lastIndexOf( fqnOfCallingClass ); if ( ibegin == -1 ) { return; } ibegin = s.indexOf( LINE_SEP, ibegin ); if ( ibegin == -1 ) { return; } ibegin += LINE_SEP_LEN; // determine end of line iend = s.indexOf( LINE_SEP, ibegin ); if ( iend == -1 ) { return; } // back up to first blank character ibegin = s.lastIndexOf( "at ", iend ); if ( ibegin == -1 ) { return; } // Add 3 to skip "at "; ibegin += 3; // everything between is the requested stack item this.fullInfo = s.substring( ibegin, iend ); } /** * Return the fully qualified class name of the caller making the logging request. * * @return the fully qualified class name of the caller making the logging request. */ public String getClassName() { if ( fullInfo == null ) { return NA; } if ( className == null ) { // Starting the search from '(' is safer because there is // potentially a dot between the parentheses. int iend = fullInfo.lastIndexOf( '(' ); if ( iend == -1 ) { className = NA; } else { iend = fullInfo.lastIndexOf( '.', iend ); // This is because a stack trace in VisualAge looks like: // java.lang.RuntimeException // java.lang.Throwable() // java.lang.Exception() // java.lang.RuntimeException() // void test.test.B.print() // void test.test.A.printIndirect() // void test.test.Run.main(java.lang.String []) final int ibegin = 0; if ( iend == -1 ) { className = NA; } else { className = this.fullInfo.substring( ibegin, iend ); } } } return className; } /** * Return the file name of the caller. * <p> * This information is not always available. * * @return the file name of the caller. */ public String getFileName() { if ( fullInfo == null ) { return NA; } if ( fileName == null ) { final int iend = fullInfo.lastIndexOf( ':' ); if ( iend == -1 ) { fileName = NA; } else { final int ibegin = fullInfo.lastIndexOf( '(', iend - 1 ); fileName = this.fullInfo.substring( ibegin + 1, iend ); } } return fileName; } /** * Returns the line number of the caller. * <p> * This information is not always available. * * @return the line number of the caller. */ public String getLineNumber() { if ( fullInfo == null ) { return NA; } if ( lineNumber == null ) { final int iend = fullInfo.lastIndexOf( ')' ); final int ibegin = fullInfo.lastIndexOf( ':', iend - 1 ); if ( ibegin == -1 ) { lineNumber = NA; } else { lineNumber = this.fullInfo.substring( ibegin + 1, iend ); } } return lineNumber; } /** * Returns the method name of the caller. * * @return the method name of the caller. */ public String getMethodName() { if ( fullInfo == null ) { return NA; } if ( methodName == null ) { final int iend = fullInfo.lastIndexOf( '(' ); final int ibegin = fullInfo.lastIndexOf( '.', iend ); if ( ibegin == -1 ) { methodName = NA; } else { methodName = this.fullInfo.substring( ibegin + 1, iend ); } } return methodName; } }