| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.log4j.selector; |
| |
| import org.apache.log4j.Hierarchy; |
| import org.apache.log4j.Level; |
| import org.apache.log4j.helpers.Constants; |
| import org.apache.log4j.helpers.IntializationUtil; |
| import org.apache.log4j.helpers.JNDIUtil; |
| import org.apache.log4j.helpers.Loader; |
| |
| import org.apache.log4j.spi.LoggerRepository; |
| import org.apache.log4j.spi.RepositorySelector; |
| import org.apache.log4j.spi.RootCategory; |
| |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.naming.Context; |
| import javax.naming.NamingException; |
| |
| |
| /** |
| * Log4j JNDI based Repository selector |
| * |
| * <p>based primarily on Ceki Gülcü's article <h3>Supporting the Log4j |
| * <code>RepositorySelector</code> in Servlet Containers</h3> at: |
| * http://qos.ch/logging/sc.html</p> |
| * |
| * <p>By default, the class static <code>RepositorySelector</code> variable |
| * of the <code>LogManager</code> class is set to a trivial |
| * <code>{@link org.apache.log4j.spi.RepositorySelector RepositorySelector}</code> |
| * implementation which always returns the same logger repository. a.k.a. |
| * hierarchy. In other words, by default log4j will use one hierarchy, the |
| * default hierarchy. This behavior can be overridden via |
| * the <code>LogManager</code>'s |
| * <code>setRepositorySelector(RepositorySelector, Object)</code> method.</p> |
| * |
| * <p>That is where this class enters the picture. It can be used to define a |
| * custom logger repository. It makes use of the fact that in J2EE |
| * environments, each web-application is guaranteed to have its own JNDI |
| * context relative to the <code>java:comp/env</code> context. In EJBs, each |
| * enterprise bean (albeit not each application) has its own context relative |
| * to the <code>java:comp/env</code> context. An <code>env-entry</code> in a |
| * deployment descriptor provides the information to the JNDI context. Once the |
| * <code>env-entry</code> is set, a repository selector can query the JNDI |
| * application context to look up the value of the entry. The logging context of |
| * the web-application will depend on the value the env-entry. The JNDI context |
| * which is looked up by this class is |
| * <code>java:comp/env/log4j/context-name</code>. |
| * |
| * <p>Here is an example of an <code>env-entry<code>: |
| * <blockquote> |
| * <pre> |
| * <env-entry> |
| * <description>JNDI logging context name for this app</description> |
| * <env-entry-name>log4j/context-name</env-entry-name> |
| * <env-entry-value>aDistinctiveLoggingContextName</env-entry-value> |
| * <env-entry-type>java.lang.String</env-entry-type> |
| * </env-entry> |
| * </pre> |
| * </blockquote> |
| * </p> |
| * |
| * <p> If multiple applications have the same logging context name, then they |
| * will share the same logging context. |
| * </p> |
| * |
| *<p>You can also specify the URL for this context's configuration resource. |
| * This repository selector (ContextJNDISelector) will use the specified resource |
| * to automatically configure the log4j repository. |
| *</p> |
| ** <blockquote> |
| * <pre> |
| * <env-entry> |
| * <description>URL for configuring log4j context</description> |
| * <env-entry-name>log4j/configuration-resource</env-entry-name> |
| * <env-entry-value>urlOfConfigrationResource</env-entry-value> |
| * <env-entry-type>java.lang.String</env-entry-type> |
| * </env-entry> |
| * </pre> |
| * </blockquote> |
| * |
| * <p>In case no configuration resource is specified, this repository selector |
| * will attempt to find the files <em>log4j.xml</em> and |
| * <em>log4j.properties</em> from the resources available to the application. |
| * </p> |
| * |
| * <p>It follows that bundling a <em>log4j.xml</em> file in your web-application |
| * and setting context name will be enough to ensure a separate logging |
| * environment for your applicaiton. |
| * |
| * <p>Given that JNDI is part of the J2EE specification, the JNDI selector |
| * is the recommended context selector. |
| * </p> |
| * |
| * @author <a href="mailto:hoju@visi.com">Jacob Kjome</a> |
| * @author Ceki Gülcü |
| * @since 1.3 |
| */ |
| public class ContextJNDISelector implements RepositorySelector { |
| |
| static String JNDI_CONFIGURATION_RESOURCE = |
| "java:comp/env/log4j/configuration-resource"; |
| static String JNDI_CONFIGURATOR_CLASS = |
| "java:comp/env/log4j/configurator-class"; |
| |
| /** |
| * key: name of logging context, |
| * value: Hierarchy instance |
| */ |
| private final Map hierMap; |
| |
| /** |
| * default hierarchy used in case the JNDI lookup |
| * fails to return a non-null value |
| */ |
| private LoggerRepository defaultRepository; |
| |
| /** |
| * public no-args constructor |
| */ |
| public ContextJNDISelector() { |
| hierMap = Collections.synchronizedMap(new HashMap()); |
| } |
| |
| public void setDefaultRepository(LoggerRepository dh) { |
| if (defaultRepository == null) { |
| defaultRepository = dh; |
| } else { |
| throw new IllegalStateException( |
| "default hierarchy has been already set."); |
| } |
| } |
| |
| /** |
| * Return the repoistory selector based on the current JNDI environment. |
| * |
| * If the respository is retreived for the first time, then also configure |
| * the repository using a user specified resource or if no such resource |
| * is specified, using the resource names "log4j.xml" or "log4j.properties". |
| * |
| * @return the appropriate JNDI-keyed context name/LoggerRepository |
| */ |
| public LoggerRepository getLoggerRepository() { |
| String loggingContextName = null; |
| Context ctx = null; |
| |
| try { |
| ctx = JNDIUtil.getInitialContext(); |
| loggingContextName = (String) JNDIUtil.lookup(ctx, Constants.JNDI_CONTEXT_NAME); |
| } catch (NamingException ne) { |
| // we can't log here |
| } |
| |
| if (loggingContextName == null) { |
| return defaultRepository; |
| } else { |
| System.out.println("loggingContextName is ["+loggingContextName+"]"); |
| Hierarchy hierarchy = (Hierarchy) hierMap.get(loggingContextName); |
| |
| if (hierarchy == null) { |
| // create new hierarchy |
| hierarchy = new Hierarchy(new RootCategory(Level.DEBUG)); |
| hierarchy.setName(loggingContextName); |
| hierMap.put(loggingContextName, hierarchy); |
| |
| // configure log4j internal logging |
| IntializationUtil.log4jInternalConfiguration(hierarchy); |
| |
| // Use automatic configration to configure the default hierarchy |
| String configResourceStr = JNDIUtil.lookup(ctx, JNDI_CONFIGURATION_RESOURCE); |
| String configuratorClassName = JNDIUtil.lookup(ctx, JNDI_CONFIGURATOR_CLASS); |
| |
| if (configResourceStr == null) { |
| if ( |
| Loader.getResource(Constants.DEFAULT_XML_CONFIGURATION_FILE) != null) { |
| configResourceStr = Constants.DEFAULT_XML_CONFIGURATION_FILE; |
| } else if ( |
| Loader.getResource(Constants.DEFAULT_CONFIGURATION_FILE) != null) { |
| configResourceStr = Constants.DEFAULT_CONFIGURATION_FILE; |
| } |
| } |
| |
| IntializationUtil.initialConfiguration( |
| hierarchy, configResourceStr, configuratorClassName); |
| } |
| |
| return hierarchy; |
| } |
| } |
| |
| |
| |
| /** |
| * Remove the repository with the given context name from the list of |
| * known repositories. |
| * |
| * @return |
| */ |
| public LoggerRepository detachRepository(String contextName) { |
| return (LoggerRepository) hierMap.remove(contextName); |
| } |
| } |