View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.logging;
8   
9   import java.lang.ref.PhantomReference;
10  import java.lang.ref.ReferenceQueue;
11  import java.util.HashMap;
12  import java.util.Map;
13  import java.util.concurrent.ConcurrentHashMap;
14  import java.util.concurrent.ConcurrentMap;
15  
16  import org.apache.log4j.LogManager;
17  import org.slf4j.ILoggerFactory;
18  import org.slf4j.Logger;
19  
20  public class MuleLoggerFactory implements ILoggerFactory
21  {
22  
23      public static final String LOG_HANDLER_THREAD_NAME = "Mule.log.slf4j.ref.handler";
24  
25      protected static final Integer NO_CCL_CLASSLOADER = 0;
26  
27      protected ConcurrentMap<Integer, ConcurrentMap<String, Logger>> repository = new ConcurrentHashMap<Integer, ConcurrentMap<String, Logger>>();
28  
29      protected ReferenceQueue<ClassLoader> referenceQueue = new ReferenceQueue<ClassLoader>();
30      // map ref back to the classloader hash for cleanup of repository map, as both Weak- and SoftReference's get() return null by this time
31      protected Map<PhantomReference<ClassLoader>, Integer> refs = new HashMap<PhantomReference<ClassLoader>, Integer>();
32  
33      public MuleLoggerFactory()
34      {
35          if (MuleUtils.isStandalone())
36          {
37              createLoggerReferenceHandler();
38          }
39      }
40  
41      protected void createLoggerReferenceHandler()
42      {
43          new LoggerReferenceHandler(LOG_HANDLER_THREAD_NAME, referenceQueue, refs, repository);
44      }
45  
46      public Logger getLogger(String name)
47      {
48          final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
49          return getLogger(name, ccl);
50      }
51  
52      public Logger getLogger(String name, ClassLoader classLoader)
53      {
54          ConcurrentMap<String, Logger> loggerMap = repository.get(classLoader == null ? NO_CCL_CLASSLOADER : classLoader.hashCode());
55  
56          if (loggerMap == null)
57          {
58              loggerMap = new ConcurrentHashMap<String, Logger>();
59              final ConcurrentMap<String, Logger> previous = repository.putIfAbsent(classLoader == null ? NO_CCL_CLASSLOADER : classLoader.hashCode(), loggerMap);
60              if (previous != null)
61              {
62                  loggerMap = previous;
63              }
64  
65              if (classLoader != null)
66              {
67                  // must save a strong ref to the PhantomReference in order for it to stay alive and work
68                  refs.put(new PhantomReference<ClassLoader>(classLoader, referenceQueue), classLoader.hashCode());
69              }
70          }
71  
72          Logger slf4jLogger = loggerMap.get(name);
73  
74          if (slf4jLogger == null)
75          {
76              org.apache.log4j.Logger log4jLogger;
77              if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
78              {
79                  log4jLogger = LogManager.getRootLogger();
80              }
81              else
82              {
83                  log4jLogger = LogManager.getLogger(name);
84              }
85              slf4jLogger = new DispatchingLogger(new AccessibleLog4jLoggerAdapter(log4jLogger), this);
86              final Logger previous = loggerMap.putIfAbsent(name, slf4jLogger);
87              if (previous != null)
88              {
89                  // someone got there before us
90                  slf4jLogger = previous;
91              }
92          }
93  
94          return slf4jLogger;
95      }
96  }