View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.impl;
18  
19  import java.net.URI;
20  
21  import org.apache.logging.log4j.core.LifeCycle;
22  import org.apache.logging.log4j.core.LoggerContext;
23  import org.apache.logging.log4j.core.config.Configuration;
24  import org.apache.logging.log4j.core.config.ConfigurationFactory;
25  import org.apache.logging.log4j.core.config.ConfigurationSource;
26  import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
27  import org.apache.logging.log4j.core.selector.ContextSelector;
28  import org.apache.logging.log4j.core.util.Constants;
29  import org.apache.logging.log4j.core.util.Loader;
30  import org.apache.logging.log4j.spi.LoggerContextFactory;
31  import org.apache.logging.log4j.status.StatusLogger;
32  import org.apache.logging.log4j.util.PropertiesUtil;
33  
34  /**
35   * Factory to locate a ContextSelector and then load a LoggerContext.
36   */
37  public class Log4jContextFactory implements LoggerContextFactory {
38  
39      private static final StatusLogger LOGGER = StatusLogger.getLogger();
40  
41      private ContextSelector selector;
42  
43      /**
44       * Initializes the ContextSelector from system property {@link Constants#LOG4J_CONTEXT_SELECTOR}.
45       */
46      public Log4jContextFactory() {
47          this(createContextSelector());
48      }
49  
50      /**
51       * Initializes this factory's ContextSelector with the specified selector.
52       * @param selector the selector to use
53       */
54      public Log4jContextFactory(final ContextSelector selector) {
55          this.selector = selector;
56      }
57  
58      private static ContextSelector createContextSelector() {
59          final String sel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR);
60          if (sel != null) {
61              try {
62                  return Loader.newCheckedInstanceOf(sel, ContextSelector.class);
63              } catch (final Exception ex) {
64                  LOGGER.error("Unable to create context {}", sel, ex);
65              }
66          }
67          return new ClassLoaderContextSelector();
68      }
69  
70      /**
71       * Loads the LoggerContext using the ContextSelector.
72       * @param fqcn The fully qualified class name of the caller.
73       * @param loader The ClassLoader to use or null.
74       * @param currentContext If true returns the current Context, if false returns the Context appropriate
75       * for the caller if a more appropriate Context can be determined.
76       * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
77       * @return The LoggerContext.
78       */
79      @Override
80      public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
81                                      final boolean currentContext) {
82          final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);
83          ctx.setExternalContext(externalContext);
84          if (ctx.getState() == LifeCycle.State.INITIALIZED) {
85              ctx.start();
86          }
87          return ctx;
88      }
89  
90      /**
91       * Loads the LoggerContext using the ContextSelector.
92       * @param fqcn The fully qualified class name of the caller.
93       * @param loader The ClassLoader to use or null.
94       * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
95       * @param currentContext If true returns the current Context, if false returns the Context appropriate
96       * for the caller if a more appropriate Context can be determined.
97       * @param source The configuration source.
98       * @return The LoggerContext.
99       */
100     public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
101                                     final boolean currentContext, final ConfigurationSource source) {
102         final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
103         if (externalContext != null && ctx.getExternalContext() == null) {
104             ctx.setExternalContext(externalContext);
105         }
106         if (ctx.getState() == LifeCycle.State.INITIALIZED) {
107             if (source != null) {
108                 ContextAnchor.THREAD_CONTEXT.set(ctx);
109                 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source);
110                 LOGGER.debug("Starting LoggerContext[name={}] from configuration {}", ctx.getName(), source);
111                 ctx.start(config);
112                 ContextAnchor.THREAD_CONTEXT.remove();
113             } else {
114                 ctx.start();
115             }
116         }
117         return ctx;
118     }
119 
120     /**
121      * Loads the LoggerContext using the ContextSelector.
122      * @param fqcn The fully qualified class name of the caller.
123      * @param loader The ClassLoader to use or null.
124      * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
125      * @param currentContext If true returns the current Context, if false returns the Context appropriate
126      * for the caller if a more appropriate Context can be determined.
127      * @param configLocation The location of the configuration for the LoggerContext.
128      * @return The LoggerContext.
129      */
130     @Override
131     public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
132                                     final boolean currentContext, final URI configLocation, final String name) {
133         final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation);
134         if (externalContext != null && ctx.getExternalContext() == null) {
135             ctx.setExternalContext(externalContext);
136         }
137         if (ctx.getState() == LifeCycle.State.INITIALIZED) {
138             if (configLocation != null || name != null) {
139                 ContextAnchor.THREAD_CONTEXT.set(ctx);
140                 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
141                 LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(), configLocation);
142                 ctx.start(config);
143                 ContextAnchor.THREAD_CONTEXT.remove();
144             } else {
145                 ctx.start();
146             }
147         }
148         return ctx;
149     }
150 
151     /**
152      * Returns the ContextSelector.
153      * @return The ContextSelector.
154      */
155     public ContextSelector getSelector() {
156         return selector;
157     }
158 
159     /**
160      * Removes knowledge of a LoggerContext.
161      *
162      * @param context The context to remove.
163      */
164     @Override
165     public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) {
166         if (context instanceof LoggerContext) {
167             selector.removeContext((LoggerContext) context);
168         }
169     }
170 }