001 /** 002 * Source code taken from {@link http://wiki.eclipse.org/EclipseLink/Foundation/Logging}. 003 * Supports use of log4j with eclipselink. 004 */ 005 package org.eclipse.persistence.logging; 006 007 import java.io.OutputStream; 008 import java.security.AccessController; 009 import java.security.PrivilegedAction; 010 import java.util.ArrayList; 011 import java.util.HashMap; 012 import java.util.List; 013 import java.util.Map; 014 import java.util.logging.Level; 015 016 import org.apache.commons.logging.Log; 017 import org.apache.commons.logging.LogFactory; 018 import org.apache.commons.logging.impl.Log4JLogger; 019 import org.apache.log4j.Logger; 020 import org.eclipse.persistence.logging.AbstractSessionLog; 021 import org.eclipse.persistence.logging.EclipseLinkLogRecord; 022 import org.eclipse.persistence.logging.JavaLog; 023 import org.eclipse.persistence.logging.SessionLog; 024 import org.eclipse.persistence.logging.SessionLogEntry; 025 import org.eclipse.persistence.sessions.Session; 026 027 /** 028 * PUBLIC: 029 * This is a wrapper class for org.apache.commons.logging.Log. 030 * It is used when messages need to be logged through apache commons logging 1.1. 031 * 032 * History : 033 * 034 * - 05/05/2009 : Updated API to EclipseLink 1.1 version + Javadoc fixes 035 * - 08/05/2009 : Fix for log4j levels in conflict with eclipselink jpa levels (shouldLog) 036 * 037 * TODO : Use Enum instead of int values for Levels (OO Design) 038 * 039 * Requires : 040 * - Jakarta Commons Logging 1.1 : http://commons.apache.org/logging/ 041 * - commons-logging-1.1.1.jar 042 * 043 * - Log4j 1.2 : http://logging.apache.org/log4j/ 044 * - log4j-1.2.15.jar 045 * 046 * 047 * @author laurent bourges (voparis) : bourges.laurent@gmail.com 048 * 049 * @see AbstractSessionLog 050 * @see JavaLog 051 * @see SessionLogEntry 052 */ 053 public final class CommonsLoggingSessionLog extends AbstractSessionLog { 054 //~ Constants -------------------------------------------------------------------------------------------------------- 055 056 /** 057 * internal debugger FLAG : use System.out 058 */ 059 public static final boolean FORCE_INTERNAL_DEBUG = false; 060 /** 061 * internal debugger FLAG : use a stack trace to find caller class 062 */ 063 public static final boolean FORCE_INTERNAL_DEBUG_STACK = false; 064 /** 065 * internal cache FLAG for LogWrapper's levels 066 */ 067 public static final boolean USE_INTERNAL_CACHE = true; 068 /** 069 * internal apache commons Logging diagnostic FLAG : use System.out 070 */ 071 public static final boolean FORCE_APACHE_COMMONS_LOGGING_DIAGNOSTICS = false; 072 /** 073 * value -1 corresponds to an undefined Level 074 */ 075 public static final int UNDEFINED_LEVEL = -1; 076 /** 077 * Stores the default session name in case there is the session name is missing. org.eclipse.persistence 078 * package used by Log4J configuration 079 */ 080 public static final String ECLIPSELINK_NAMESPACE = "org.eclipse.persistence"; 081 /** 082 * org.eclipse.persistence.default used by Log4J configuration 083 */ 084 public static final String DEFAULT_ECLIPSELINK_NAMESPACE = ECLIPSELINK_NAMESPACE + ".default"; 085 /** 086 * org.eclipse.persistence.session used by Log4J configuration 087 */ 088 public static final String SESSION_ECLIPSELINK_NAMESPACE = ECLIPSELINK_NAMESPACE + ".session"; 089 /** 090 * Copied from JavaLog for compatibility issues 091 */ 092 public static final String LOGGING_LOCALIZATION_STRING = "org.eclipse.persistence.internal.localization.i18n.LoggingLocalizationResource"; 093 /** 094 * Copied from JavaLog for compatibility issues 095 */ 096 public static final String TRACE_LOCALIZATION_STRING = "org.eclipse.persistence.internal.localization.i18n.TraceLocalizationResource"; 097 /** 098 * Stores all the java.util.logging.Levels. The indexes are EclipseLink logging levels. 099 */ 100 public static final Level[] JAVA_LEVELS = new Level[]{ 101 Level.ALL, Level.FINEST, Level.FINER, Level.FINE, Level.CONFIG, Level.INFO, 102 Level.WARNING, Level.SEVERE, Level.OFF 103 }; 104 105 106 static { 107 /* static Initializer to call onInit method */ 108 onInit(); 109 } 110 111 //~ Members ---------------------------------------------------------------------------------------------------------- 112 /** 113 * formats the EclipseLinkLogRecords. Acts as a static variable but not declared static to avoid classLoader 114 * leaks (clone does not deep clone this instance) 115 */ 116 private final FastLogFormatter LOG_FORMATTER = new FastLogFormatter(); 117 /** 118 * Represents the HashMap that stores all the name space strings. The keys are category names. The values are 119 * namespace strings. Acts as a static variable but not declared static to avoid classLoader leaks (clone does not 120 * deep clone this map). Note : Unsynchronized Map = should be thread-safe ! 121 */ 122 private final Map<String, String> NAMESPACE_MAP = new HashMap<String, String>(32); 123 /** 124 * LogWrapper instances. Acts as a static variable but not declared static to avoid classLoader leaks (clone 125 * does not deep clone this map) Note : Unsynchronized Map = should be thread-safe ! 126 */ 127 private final Map<String, LogWrapper> CATEGORY_LOGGERS = new HashMap<String, LogWrapper>(32); 128 /** 129 * Stores the namespace for session, i.e."org.eclipse.persistence.session.#sessionname#". 130 */ 131 private String sessionNameSpace; 132 133 //~ Constructors ----------------------------------------------------------------------------------------------------- 134 /** 135 * PUBLIC: 136 * 137 * CommonsLoggingSessionLog Constructor. 138 * 139 * Used by : 140 * org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.updateLoggers : 141 * creates an instance for singletonLog and sessionLog 142 * 143 * This adds a root logger for DEFAULT_ECLIPSELINK_NAMESPACE. 144 */ 145 public CommonsLoggingSessionLog() { 146 super(); 147 148 if (FORCE_INTERNAL_DEBUG) { 149 debug("CommonsLoggingSessionLog.new : instance : " + this, true); 150 } 151 152 addLogger(DEFAULT_ECLIPSELINK_NAMESPACE, DEFAULT_ECLIPSELINK_NAMESPACE); 153 } 154 155 //~ Methods ---------------------------------------------------------------------------------------------------------- 156 /** 157 * PUBLIC: 158 * 159 * OnInit method : define system properties for org.apache.commons.logging 160 */ 161 public static final void onInit() { 162 163 if (FORCE_APACHE_COMMONS_LOGGING_DIAGNOSTICS) { 164 /** 165 * The name (<code>org.apache.commons.logging.diagnostics.dest</code>) 166 * of the property used to enable internal commons-logging 167 * diagnostic output, in order to get information on what logging 168 * implementations are being discovered, what classloaders they 169 * are loaded through, etc. 170 * <p> 171 * If a system property of this name is set then the value is 172 * assumed to be the name of a file. The special strings 173 * STDOUT or STDERR (case-sensitive) indicate output to 174 * System.out and System.err respectively. 175 * <p> 176 * Diagnostic logging should be used only to debug problematic 177 * configurations and should not be set in normal production use. 178 */ 179 System.setProperty("org.apache.commons.logging.diagnostics.dest", "STDOUT"); 180 } 181 } 182 183 /** 184 * PUBLIC: 185 * 186 * onExit method : release all ClassLoader references due to apache commons logging LogFactory 187 * 188 * NOTE : <b>This method must be called in the context of a web application via ServletContextListener.contextDestroyed(ServletContextEvent)</b> 189 * 190 * @see org.apache.commons.logging.LogFactory#release(ClassLoader) 191 */ 192 public static final void onExit() { 193 // Classloader unload problem with commons-logging : 194 LogFactory.release(Thread.currentThread().getContextClassLoader()); 195 } 196 197 /** 198 * PUBLIC: Return the effective log level for the name space extracted from session and category. If a 199 * Logger's level is set to be null then the Logger will use an effective Level that will be obtained by walking up 200 * the parent tree and using the first non-null Level. 201 * 202 * @param category category 203 * 204 * @return the effective level according to the java.util.logging.Levels 205 */ 206 @Override 207 public final int getLevel(final String category) { 208 if (FORCE_INTERNAL_DEBUG) { 209 debug("CommonsLoggingSessionLog.getLevel : IN : category : " + category); 210 } 211 212 final LogWrapper lw = getLogWrapper(category); 213 214 int l = OFF; 215 216 if (lw != null) { 217 l = lw.getLevel(); 218 } 219 220 if (FORCE_INTERNAL_DEBUG) { 221 debug("CommonsLoggingSessionLog.getLevel : OUT : category : " + category + " : level : " + getLevelString(l)); 222 } 223 224 return l; 225 } 226 227 /** 228 * PUBLIC: Set the log level to a logger with name space extracted from the given category. 229 * 230 * @param level value according to the java.util.logging.Levels 231 * @param category category 232 */ 233 @Override 234 public final void setLevel(final int level, final String category) { 235 AccessController.doPrivileged( 236 new PrivilegedAction<Object>() { 237 238 public Object run() { 239 if (FORCE_INTERNAL_DEBUG) { 240 debug("CommonsLoggingSessionLog.setLevel : IN : category : " + category + " to level : " + 241 getLevelString(level), true); 242 } 243 244 final LogWrapper lw = getLogWrapper(category); 245 246 if (lw == null) { 247 error("CommonsLoggingSessionLog.setLevel : category not found : " + category); 248 } else { 249 final Logger logger = getLog4JLogger(lw.getLog()); 250 251 if (logger == null) { 252 error("CommonsLoggingSessionLog.setLevel : Logger not found : " + category + " : " + lw.getLog()); 253 } else { 254 255 final org.apache.log4j.Level realLevel = getLevelFor(level); 256 257 if (realLevel == org.apache.log4j.Level.OFF) { 258 // force level to OFF : 259 lw.setLevel(OFF); 260 error("CommonsLoggingSessionLog.setLevel : unknown level : " + getLevelString(level) + " : level set to OFF"); 261 } else { 262 lw.setLevel(level); 263 } 264 logger.setLevel(realLevel); 265 266 if (logger.isEnabledFor(org.apache.log4j.Level.WARN)) { 267 logger.warn("CommonsLoggingSessionLog.setLevel : Logger Level set to : " + logger.getLevel()); 268 } 269 270 if (FORCE_INTERNAL_DEBUG) { 271 debug("CommonsLoggingSessionLog.setLevel : OUT : category : " + category + " to level : " + 272 logger.getLevel()); 273 } 274 } 275 } 276 277 // nothing to return : 278 return null; 279 } 280 }); 281 } 282 283 /** 284 * PUBLIC: Set the output stream that will receive the formatted log entries. DO nothing as Log4J manages the 285 * appenders (console or files) via Log4J configuration 286 * 287 * @param fileOutputStream the file output stream will receive the formatted log entries. 288 */ 289 @Override 290 public final void setWriter(final OutputStream fileOutputStream) { 291 if (FORCE_INTERNAL_DEBUG) { 292 debug("CommonsLoggingSessionLog.setWriter : stream : " + fileOutputStream); 293 } 294 295 // do nothing 296 } 297 298 /** 299 * PUBLIC: Set the session and session namespace. 300 * 301 * @param pSession an eclipselink Session 302 */ 303 @Override 304 public final void setSession(final Session pSession) { 305 super.setSession(pSession); 306 307 if (pSession != null) { 308 final String sessionName = pSession.getName(); 309 310 if ((sessionName != null) && (sessionName.length() != 0)) { 311 this.sessionNameSpace = SESSION_ECLIPSELINK_NAMESPACE + "." + sessionName; 312 } else { 313 this.sessionNameSpace = DEFAULT_ECLIPSELINK_NAMESPACE; 314 } 315 316 if (FORCE_INTERNAL_DEBUG) { 317 debug("CommonsLoggingSessionLog.setSession : sessionNameSpace : " + this.sessionNameSpace); 318 } 319 320 //Initialize loggers eagerly 321 addLogger(this.sessionNameSpace, this.sessionNameSpace); 322 323 addDefaultLoggers(this.sessionNameSpace); 324 } 325 } 326 327 /** 328 * PUBLIC: Check if a message of the given lev would actually be logged by the logger with name space built 329 * from the given session and category. Return the shouldLog for the given category Note : this method is very very 330 * used so optimized for performance. 331 * 332 * @param level value according to the java.util.logging.Levels 333 * @param category category 334 * 335 * @return true if the given message will be logged 336 */ 337 @Override 338 public final boolean shouldLog(final int level, final String category) { 339 if (FORCE_INTERNAL_DEBUG) { 340 debug("CommonsLoggingSessionLog.shouldLog : IN : category : " + category + " : " + getLevelString(level)); 341 } 342 343 boolean res = false; 344 345 switch (level) { 346 case OFF: 347 res = false; 348 349 break; 350 351 case ALL: 352 res = true; 353 354 break; 355 356 default: 357 358 final LogWrapper lw = getLogWrapper(category); 359 360 if (lw == null) { 361 error("CommonsLoggingSessionLog.shouldLog : category : " + category + " - NO LOGGER FOUND"); 362 res = false; 363 } else { 364 res = level >= lw.getLevel(); 365 } 366 } 367 368 if (FORCE_INTERNAL_DEBUG) { 369 debug("CommonsLoggingSessionLog.shouldLog : OUT : category : " + category + " : " + res); 370 } 371 372 return res; 373 } 374 375 /** 376 * PUBLIC: Log a SessionLogEntry 377 * 378 * @param entry SessionLogEntry that holds all the information for a EclipseLink logging event 379 */ 380 public final void log(final SessionLogEntry entry) { 381 if (shouldLog(entry.getLevel(), entry.getNameSpace())) { 382 if (FORCE_INTERNAL_DEBUG) { 383 debug("CommonsLoggingSessionLog.log : namespace : " + entry.getNameSpace() + " message : " + entry.getMessage()); 384 } 385 386 final Log log = getLog(entry.getNameSpace()); 387 388 if (log == null) { 389 error("CommonsLoggingSessionLog.log : no Log found for : " + entry.getNameSpace()); 390 } else { 391 final Level javaLevel = getJavaLevel(entry.getLevel()); 392 393 internalLog(entry, javaLevel, log); 394 } 395 } 396 } 397 398 /** 399 * PUBLIC: Log a throwable. 400 * 401 * @param throwable a throwable 402 */ 403 @Override 404 public final void throwing(final Throwable throwable) { 405 final Log log = getLog(null); 406 407 if (log != null) { 408 log.error(null, throwable); 409 } 410 } 411 412 /** 413 * INTERNAL: Each session owns its own session log because session is stored in the session log 414 * 415 * @return value TODO : Value Description 416 */ 417 @Override 418 public final Object clone() { 419 // There is no special treatment required for cloning here 420 // The state of this object is described by member variables sessionLogger and categoryLoggers. 421 // This state depends on session. 422 // If session for the clone is going to be the same as session for this there is no 423 // need to do "deep" cloning. 424 // If not, the session being cloned should call setSession() on its JavaLog object to initialize it correctly. 425 final CommonsLoggingSessionLog cloneLog = (CommonsLoggingSessionLog) super.clone(); 426 427 if (FORCE_INTERNAL_DEBUG) { 428 debug("CommonsLoggingSessionLog.clone : cloned instance : " + cloneLog, true); 429 } 430 431 return cloneLog; 432 } 433 434 /** 435 * INTERNAL: Add Logger to the categoryloggers. 436 * 437 * @param loggerCategory category 438 * @param loggerNameSpace name space 439 */ 440 private final void addLogger(final String loggerCategory, final String loggerNameSpace) { 441 if (FORCE_INTERNAL_DEBUG) { 442 debug("CommonsLoggingSessionLog.addLogger : category : " + loggerCategory + " in name space : " + loggerNameSpace); 443 } 444 445 this.CATEGORY_LOGGERS.put(loggerCategory, new LogWrapper(this, loggerCategory, LogFactory.getLog(loggerNameSpace))); 446 } 447 448 /** 449 * INTERNAL: Return the name space for the given category from the map. 450 * 451 * @param category category 452 * 453 * @return name space for the given category 454 */ 455 private final String getNameSpaceString(final String category) { 456 if (getSession() == null) { 457 return DEFAULT_ECLIPSELINK_NAMESPACE; 458 } else if ((category == null) || (category.length() == 0)) { 459 return this.sessionNameSpace; 460 } else { 461 return this.NAMESPACE_MAP.get(category); 462 } 463 } 464 465 /** 466 * INTERNAL: Return the LogWrapper instance for the given category Note : this method is very very used so 467 * optimized for performance. 468 * 469 * @param category category 470 * 471 * @return LogWrapper instance or null if not found 472 */ 473 private final LogWrapper getLogWrapper(final String category) { 474 LogWrapper lw = null; 475 476 if (getSession() == null) { 477 if (FORCE_INTERNAL_DEBUG) { 478 debug("CommonsLoggingSessionLog.getLogWrapper : " + category + " : SESSION NULL"); 479 } 480 481 lw = this.CATEGORY_LOGGERS.get(DEFAULT_ECLIPSELINK_NAMESPACE); 482 } else { 483 lw = this.CATEGORY_LOGGERS.get(category); 484 485 if (lw == null) { 486 if (FORCE_INTERNAL_DEBUG) { 487 debug("CommonsLoggingSessionLog.getLogWrapper : " + category + " : CATEGORY IS NULL ?"); 488 } 489 490 // really few cases : 491 if ((category == null) || (category.length() == 0)) { 492 lw = this.CATEGORY_LOGGERS.get(this.sessionNameSpace); 493 } 494 } 495 } 496 497 if (FORCE_INTERNAL_DEBUG) { 498 debug("CommonsLoggingSessionLog.getLogWrapper : " + category + " = " + lw); 499 } 500 501 return lw; 502 } 503 504 /** 505 * INTERNAL: Return the apache commons logging Log instance for the given category 506 * 507 * @param category category 508 * 509 * @return value Log instance or null if not found 510 */ 511 private final Log getLog(final String category) { 512 if (FORCE_INTERNAL_DEBUG) { 513 debug("CommonsLoggingSessionLog.getLogger : IN : category : " + category); 514 } 515 516 final LogWrapper lw = getLogWrapper(category); 517 518 Log log = null; 519 520 if (lw != null) { 521 log = lw.getLog(); 522 } 523 524 if (FORCE_INTERNAL_DEBUG) { 525 debug("CommonsLoggingSessionLog.getLogger : OUT : log : " + log); 526 } 527 528 return log; 529 } 530 531 /** 532 * INTERNAL: Adds default loggers for the given name space 533 * 534 * @param namespace name space 535 */ 536 private final void addDefaultLoggers(final String namespace) { 537 if (FORCE_INTERNAL_DEBUG) { 538 debug("CommonsLoggingSessionLog.addDefaultLoggers : nameSpace : " + namespace); 539 } 540 541 String loggerCategory; 542 String loggerNameSpace; 543 544 final String[] categories = SessionLog.loggerCatagories; 545 546 final int size = categories.length; 547 548 for (int i = 0; i < size; i++) { 549 loggerCategory = categories[i]; 550 loggerNameSpace = namespace + "." + loggerCategory; 551 552 this.NAMESPACE_MAP.put(loggerCategory, loggerNameSpace); 553 addLogger(loggerCategory, loggerNameSpace); 554 } 555 556 if (FORCE_INTERNAL_DEBUG) { 557 debug("CommonsLoggingSessionLog.addDefaultLoggers : NAMESPACE_MAP : " + this.NAMESPACE_MAP); 558 debug("CommonsLoggingSessionLog.addDefaultLoggers : CATEGORY_LOGGERS : " + this.CATEGORY_LOGGERS); 559 } 560 } 561 562 /** 563 * INTERNAL: Build a LogRecord 564 * 565 * @param entry SessionLogEntry that holds all the information for a EclipseLink logging event 566 * @param level according to eclipselink level 567 * @param log commons-logging 1.1 wrapper 568 */ 569 private final void internalLog(final SessionLogEntry entry, final Level level, final Log log) { 570 if (FORCE_INTERNAL_DEBUG) { 571 debug("CommonsLoggingSessionLog.internalLog : " + computeMessage(entry, level)); 572 } 573 574 final int entryLevel = entry.getLevel(); 575 576 switch (entryLevel) { 577 case SEVERE: 578 log.error(computeMessage(entry, level)); 579 580 break; 581 582 case WARNING: 583 log.warn(computeMessage(entry, level)); 584 585 break; 586 587 case INFO: 588 case CONFIG: 589 log.info(computeMessage(entry, level)); 590 591 break; 592 593 case FINE: 594 case FINER: 595 case FINEST: 596 log.debug(computeMessage(entry, level)); 597 598 break; 599 600 case ALL: 601 log.trace(computeMessage(entry, level)); 602 603 break; 604 605 case OFF: 606 break; 607 608 default: 609 error("CommonsLoggingSessionLog.internalLog : unknown level : " + entryLevel); 610 611 break; 612 } 613 } 614 615 /** 616 * INTERNAL: Computes the log message 617 * 618 * @param entry SessionLogEntry that holds all the information for a EclipseLink logging event 619 * @param level according to eclipselink level 620 * 621 * @return value TODO : Value Description 622 */ 623 private final String computeMessage(final SessionLogEntry entry, final Level level) { 624 // Format message so that we do not depend on the bundle 625 final EclipseLinkLogRecord lr = new EclipseLinkLogRecord(level, formatMessage(entry)); 626 627 lr.setSourceClassName(null); 628 lr.setSourceMethodName(null); 629 lr.setLoggerName(getNameSpaceString(entry.getNameSpace())); 630 631 if (shouldPrintSession()) { 632 lr.setSessionString(getSessionString(entry.getSession())); 633 } 634 635 if (shouldPrintConnection()) { 636 lr.setConnection(entry.getConnection()); 637 } 638 639 lr.setThrown(entry.getException()); 640 lr.setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace()); 641 642 lr.setShouldPrintDate(shouldPrintDate()); 643 lr.setShouldPrintThread(shouldPrintThread()); 644 645 return this.LOG_FORMATTER.format(lr); 646 } 647 648 /** 649 * INTERNAL: Return the corresponding java.util.logging.Level for a given eclipselink level. 650 * 651 * @param level according to eclipselink level 652 * 653 * @return value according to the java.util.logging.Levels 654 */ 655 private static final Level getJavaLevel(final int level) { 656 return JAVA_LEVELS[level]; 657 } 658 659 /** 660 * INTERNAL: Returns Log4JLogger instance 661 * 662 * @param log commons-logging 1.1 wrapper 663 * 664 * @return Log4JLogger instance 665 */ 666 private static final Logger getLog4JLogger(final Log log) { 667 Logger l = null; 668 669 if (log instanceof Log4JLogger) { 670 l = ((Log4JLogger) log).getLogger(); 671 } 672 673 if (FORCE_INTERNAL_DEBUG) { 674 debug("CommonsLoggingSessionLog.getLog4JLogger : " + l); 675 } 676 677 return l; 678 } 679 680 /** 681 * PUBLIC: SHOULD BE in AbstractSessionLog 682 * 683 * @see AbstractSessionLog#getLevelString() Return the log level as a string value. 684 */ 685 private static final String getLevelString(final int level) { 686 switch (level) { 687 case OFF: 688 return "OFF"; 689 690 case SEVERE: 691 return "SEVERE"; 692 693 case WARNING: 694 return "WARNING"; 695 696 case INFO: 697 return "INFO"; 698 699 case CONFIG: 700 return "CONFIG"; 701 702 case FINE: 703 return "FINE"; 704 705 case FINER: 706 return "FINER"; 707 708 case FINEST: 709 return "FINEST"; 710 711 case ALL: 712 return "ALL"; 713 714 default: 715 return "INFO"; 716 } 717 } 718 719 /** 720 * Returns the real Log4J Level 721 * @param level eclipselink level 722 * @return org.apache.log4j.Level 723 */ 724 private static final org.apache.log4j.Level getLevelFor(final int level) { 725 org.apache.log4j.Level realLevel = null; 726 switch (level) { 727 case SEVERE: 728 realLevel = org.apache.log4j.Level.ERROR; 729 730 break; 731 732 case WARNING: 733 realLevel = org.apache.log4j.Level.WARN; 734 735 break; 736 737 case INFO: 738 case CONFIG: 739 realLevel = org.apache.log4j.Level.INFO; 740 741 break; 742 743 case FINE: 744 case FINER: 745 case FINEST: 746 realLevel = org.apache.log4j.Level.DEBUG; 747 748 break; 749 750 case ALL: 751 realLevel = org.apache.log4j.Level.ALL; 752 753 break; 754 755 case OFF: 756 realLevel = org.apache.log4j.Level.OFF; 757 758 break; 759 760 default: 761 realLevel = org.apache.log4j.Level.OFF; 762 error("CommonsLoggingSessionLog.getLevelFor : unknown level : " + getLevelString(level) + " = OFF"); 763 764 break; 765 } 766 if (FORCE_INTERNAL_DEBUG) { 767 debug("CommonsLoggingSessionLog.getLevelFor : level : " + getLevelString(level) + " = " + realLevel); 768 } 769 return realLevel; 770 771 } 772 773 /** 774 * Prints the message in Std out 775 * @param message message to print 776 */ 777 protected final static void debug(final String message) { 778 debug(message, false); 779 } 780 781 /** 782 * Prints the message in Std out 783 * @param message message to print 784 * @param printStack adds a stack trace to find caller class 785 */ 786 protected final static void debug(final String message, final boolean printStack) { 787 System.out.println(message); 788 // if (printStack && FORCE_INTERNAL_DEBUG_STACK) { 789 // // to inspect the calling stack : 790 // new Throwable().printStackTrace(System.out); 791 // } 792 } 793 794 /** 795 * Prints the message in Std err 796 * @param message message to print 797 */ 798 protected final static void error(final String message) { 799 System.err.println(message); 800 } 801 802 /** 803 * Prints the message in Std err 804 * @param message message to print 805 */ 806 protected final static void error(final Throwable th) { 807 th.printStackTrace(System.err); 808 } 809 810 //~ Inner Classes ---------------------------------------------------------------------------------------------------- 811 /** 812 * INTERNAL: LogWrapper class wraps the real apache commons logging Log instance 813 */ 814 private static final class LogWrapper { 815 //~ Members -------------------------------------------------------------------------------------------------------- 816 817 /** parent CommonsLoggingSessionLog instance */ 818 private final CommonsLoggingSessionLog sessionLog; 819 /** category for debug mode */ 820 private final String category; 821 /** apache commons logging Log instance */ 822 private final Log log; 823 /** parent LogWrapper */ 824 private final LogWrapper parent; 825 /** child LogWrapper instances */ 826 private List<LogWrapper> children = null; 827 /** level as defined by java.util.logging.Levels. Can be changed at runtime */ 828 private int level = UNDEFINED_LEVEL; 829 /** cached level as defined by java.util.logging.Levels. Extracted from parent LogWrapper instances */ 830 private int cachedLevel = UNDEFINED_LEVEL; 831 832 //~ Constructors --------------------------------------------------------------------------------------------------- 833 /** 834 * INTERNAL: 835 * 836 * Constructor 837 * 838 * @param log apache commons logging Log instance 839 */ 840 protected LogWrapper(final CommonsLoggingSessionLog sessionLog, final String category, final Log log) { 841 this.sessionLog = sessionLog; 842 this.category = category; 843 this.log = log; 844 845 final Logger logger = CommonsLoggingSessionLog.getLog4JLogger(log); 846 847 String parentName = null; 848 849 if (logger != null) { 850 parentName = logger.getParent().getName(); 851 } 852 853 if ((parentName != null) && !"null".equals(parentName)) { 854 if (FORCE_INTERNAL_DEBUG) { 855 debug("CommonsLoggingSessionLog.LogWrapper.new : parent : " + parentName); 856 } 857 858 this.parent = this.sessionLog.getLogWrapper(parentName); 859 860 if (this.parent != null) { 861 this.parent.addChild(this); 862 } 863 } else { 864 this.parent = null; 865 } 866 } 867 868 //~ Methods -------------------------------------------------------------------------------------------------------- 869 /** 870 * INTERNAL: Returns the category 871 * 872 * @return category 873 */ 874 protected final String getCategory() { 875 return this.category; 876 } 877 878 /** 879 * INTERNAL: Reset the cachedLevel 880 */ 881 protected final void resetCachedLevel() { 882 this.cachedLevel = UNDEFINED_LEVEL; 883 884 if (FORCE_INTERNAL_DEBUG) { 885 debug("CommonsLoggingSessionLog.LogWrapper.setLevel : reset cachedLevel for : " + getCategory()); 886 } 887 } 888 889 /** 890 * INTERNAL: Returns the apache commons logging Log instance 891 * 892 * @return apache commons logging Log instance 893 */ 894 protected final Log getLog() { 895 return this.log; 896 } 897 898 /** 899 * INTERNAL: Returns the level according to the java.util.logging.Levels 900 * 901 * @return level computed from cachedLevel and internal level 902 */ 903 protected final int getLevel() { 904 int res = this.cachedLevel; 905 906 // if the cachedLevel is undefined : compute it from parents : 907 if (res == UNDEFINED_LEVEL) { 908 // first gives the internal level : 909 res = this.level; 910 911 if (FORCE_INTERNAL_DEBUG) { 912 System.out.println( 913 "CommonsLoggingSessionLog.LogWrapper.getLevel : this : " + getCategory() + " : UNCACHED level : " + getLevelString(res)); 914 } 915 916 if (res == UNDEFINED_LEVEL) { 917 res = computeLevel(UNDEFINED_LEVEL); 918 919 if (USE_INTERNAL_CACHE) { 920 this.cachedLevel = res; 921 } 922 } 923 } 924 return res; 925 } 926 927 /** 928 * INTERNAL: Defines the level according to the java.util.logging.Levels 929 * 930 * @param level value according to the java.util.logging.Levels 931 */ 932 protected final void setLevel(final int level) { 933 this.level = level; 934 935 if (USE_INTERNAL_CACHE) { 936 this.resetCachedLevel(); 937 if (this.children != null) { 938 // reset cachedLevel for all children : 939 for (final LogWrapper cw : this.children) { 940 cw.resetCachedLevel(); 941 } 942 } 943 } 944 } 945 946 /** 947 * INTERNAL: Adds a child LogWrapper 948 * 949 * @param lw 950 */ 951 protected final void addChild(final LogWrapper lw) { 952 if (this.children == null) { 953 this.children = new ArrayList<LogWrapper>(); 954 } 955 956 this.children.add(lw); 957 958 if (FORCE_INTERNAL_DEBUG) { 959 System.out.println( 960 "CommonsLoggingSessionLog.LogWrapper.addChild : this : " + getCategory() + " : child : " + lw.getCategory()); 961 } 962 } 963 964 /** 965 * INTERNAL: Computes the cached Level 966 * 967 * @param localLevel this.level copy 968 * 969 * @return level 970 */ 971 private final int computeLevel(final int localLevel) { 972 LogWrapper pw; 973 LogWrapper lw = this; 974 975 if (FORCE_INTERNAL_DEBUG) { 976 System.out.println( 977 "CommonsLoggingSessionLog.LogWrapper.computeLevel : IN : " + getCategory() + " : level : " + 978 CommonsLoggingSessionLog.getLevelString(localLevel)); 979 } 980 981 while ((lw != null) && 982 (((lw == this) && (localLevel == UNDEFINED_LEVEL)) || 983 ((lw != this) && (lw.getLevel() == UNDEFINED_LEVEL)))) { 984 pw = lw.parent; 985 986 if (pw != lw) { 987 lw = pw; 988 } else { 989 // exit from loop : 990 lw = null; 991 } 992 } 993 994 int computedLevel = OFF; 995 996 if (lw != null) { 997 computedLevel = lw.getLevel(); 998 999 if (FORCE_INTERNAL_DEBUG) { 1000 System.out.println( 1001 "CommonsLoggingSessionLog.LogWrapper.computeLevel : category : " + lw.getCategory() + " - computedLevel : " + getLevelString(computedLevel) + " : " + lw.getLog()); 1002 } 1003 final Logger logger = getLog4JLogger(lw.getLog()); 1004 1005 if (logger == null) { 1006 error("CommonsLoggingSessionLog.computeLevel : Logger not found : " + lw.getCategory() + " : " + lw.getLog()); 1007 } else { 1008 1009 final org.apache.log4j.Level realLevel = getLevelFor(computedLevel); 1010 1011 final boolean enabled = logger.isEnabledFor(realLevel); 1012 1013 if (!enabled) { 1014 computedLevel = OFF; 1015 } 1016 if (FORCE_INTERNAL_DEBUG) { 1017 System.out.println( 1018 "CommonsLoggingSessionLog.LogWrapper.computeLevel : category : " + lw.getCategory() + " : realLevel : " + realLevel + " - enabled = " + enabled); 1019 } 1020 } 1021 1022 1023 } 1024 1025 if (FORCE_INTERNAL_DEBUG) { 1026 System.out.println( 1027 "CommonsLoggingSessionLog.LogWrapper.computeLevel : OUT : " + getCategory() + " : level : " + 1028 CommonsLoggingSessionLog.getLevelString(computedLevel)); 1029 } 1030 1031 return computedLevel; 1032 } 1033 } 1034 } 1035 //~ End of file --------------------------------------------------------------------------------------------------------