+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-// WARNING This class MUST not have references to the Category or
-// WARNING RootCategory classes in its static initiliazation neither
-// WARNING directly nor indirectly.
-
-// Contributors:
-// Luke Blanshard <luke@quiq.com>
-// Mario Schomburg - IBM Global Services/Germany
-// Anders Kristensen
-// Igor Poteryaev
-
-package org.apache.log4j;
-
-
-import java.util.Hashtable;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import org.apache.log4j.spi.LoggerFactory;
-import org.apache.log4j.spi.HierarchyEventListener;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.RendererSupport;
-import org.apache.log4j.or.RendererMap;
-import org.apache.log4j.or.ObjectRenderer;
-import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.spi.ThrowableRendererSupport;
-import org.apache.log4j.spi.ThrowableRenderer;
-
-/**
- This class is specialized in retrieving loggers by name and also
- maintaining the logger hierarchy.
-
- <p><em>The casual user does not have to deal with this class
- directly.</em>
-
- <p>The structure of the logger hierarchy is maintained by the
- {@link #getLogger} method. The hierarchy is such that children link
- to their parent but parents do not have any pointers to their
- children. Moreover, loggers can be instantiated in any order, in
- particular descendant before ancestor.
-
- <p>In case a descendant is created before a particular ancestor,
- then it creates a provision node for the ancestor and adds itself
- to the provision node. Other descendants of the same ancestor add
- themselves to the previously created provision node.
-
- @author Ceki Gülcü
-
-*/
-public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
-
- private LoggerFactory defaultFactory;
- private Vector listeners;
-
- Hashtable ht;
- Logger root;
- RendererMap rendererMap;
-
- int thresholdInt;
- Level threshold;
-
- boolean emittedNoAppenderWarning = false;
- boolean emittedNoResourceBundleWarning = false;
-
- private ThrowableRenderer throwableRenderer = null;
-
- /**
- Create a new logger hierarchy.
-
- @param root The root of the new hierarchy.
-
- */
- public
- Hierarchy(Logger root) {
- ht = new Hashtable();
- listeners = new Vector(1);
- this.root = root;
- // Enable all level levels by default.
- setThreshold(Level.ALL);
- this.root.setHierarchy(this);
- rendererMap = new RendererMap();
- defaultFactory = new DefaultCategoryFactory();
- }
-
- /**
- Add an object renderer for a specific class.
- */
- public
- void addRenderer(Class classToRender, ObjectRenderer or) {
- rendererMap.put(classToRender, or);
- }
-
- public
- void addHierarchyEventListener(HierarchyEventListener listener) {
- if(listeners.contains(listener)) {
- LogLog.warn("Ignoring attempt to add an existent listener.");
- } else {
- listeners.addElement(listener);
- }
- }
-
- /**
- This call will clear all logger definitions from the internal
- hashtable. Invoking this method will irrevocably mess up the
- logger hierarchy.
-
- <p>You should <em>really</em> know what you are doing before
- invoking this method.
-
- @since 0.9.0 */
- public
- void clear() {
- //System.out.println("\n\nAbout to clear internal hash table.");
- ht.clear();
- }
-
- public
- void emitNoAppenderWarning(Category cat) {
- // No appenders in hierarchy, warn user only once.
- if(!this.emittedNoAppenderWarning) {
- LogLog.warn("No appenders could be found for logger (" +
- cat.getName() + ").");
- LogLog.warn("Please initialize the log4j system properly.");
- LogLog.warn("See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.");
- this.emittedNoAppenderWarning = true;
- }
- }
-
- /**
- Check if the named logger exists in the hierarchy. If so return
- its reference, otherwise returns <code>null</code>.
-
- @param name The name of the logger to search for.
-
- */
- public
- Logger exists(String name) {
- Object o = ht.get(new CategoryKey(name));
- if(o instanceof Logger) {
- return (Logger) o;
- } else {
- return null;
- }
- }
-
- /**
- The string form of {@link #setThreshold(Level)}.
- */
- public
- void setThreshold(String levelStr) {
- Level l = Level.toLevel(levelStr, null);
- if(l != null) {
- setThreshold(l);
- } else {
- LogLog.warn("Could not convert ["+levelStr+"] to Level.");
- }
- }
-
-
- /**
- Enable logging for logging requests with level <code>l</code> or
- higher. By default all levels are enabled.
-
- @param l The minimum level for which logging requests are sent to
- their appenders. */
- public
- void setThreshold(Level l) {
- if(l != null) {
- thresholdInt = l.level;
- threshold = l;
- }
- }
-
- public
- void fireAddAppenderEvent(Category logger, Appender appender) {
- if(listeners != null) {
- int size = listeners.size();
- HierarchyEventListener listener;
- for(int i = 0; i < size; i++) {
- listener = (HierarchyEventListener) listeners.elementAt(i);
- listener.addAppenderEvent(logger, appender);
- }
- }
- }
-
- void fireRemoveAppenderEvent(Category logger, Appender appender) {
- if(listeners != null) {
- int size = listeners.size();
- HierarchyEventListener listener;
- for(int i = 0; i < size; i++) {
- listener = (HierarchyEventListener) listeners.elementAt(i);
- listener.removeAppenderEvent(logger, appender);
- }
- }
- }
-
- /**
- Returns a {@link Level} representation of the <code>enable</code>
- state.
-
- @since 1.2 */
- public
- Level getThreshold() {
- return threshold;
- }
-
- /**
- Returns an integer representation of the this repository's
- threshold.
-
- @since 1.2 */
- //public
- //int getThresholdInt() {
- // return thresholdInt;
- //}
-
-
- /**
- Return a new logger instance named as the first parameter using
- the default factory.
-
- <p>If a logger of that name already exists, then it will be
- returned. Otherwise, a new logger will be instantiated and
- then linked with its existing ancestors as well as children.
-
- @param name The name of the logger to retrieve.
-
- */
- public
- Logger getLogger(String name) {
- return getLogger(name, defaultFactory);
- }
-
- /**
- Return a new logger instance named as the first parameter using
- <code>factory</code>.
-
- <p>If a logger of that name already exists, then it will be
- returned. Otherwise, a new logger will be instantiated by the
- <code>factory</code> parameter and linked with its existing
- ancestors as well as children.
-
- @param name The name of the logger to retrieve.
- @param factory The factory that will make the new logger instance.
-
- */
- public
- Logger getLogger(String name, LoggerFactory factory) {
- //System.out.println("getInstance("+name+") called.");
- CategoryKey key = new CategoryKey(name);
- // Synchronize to prevent write conflicts. Read conflicts (in
- // getChainedLevel method) are possible only if variable
- // assignments are non-atomic.
- Logger logger;
-
- synchronized(ht) {
- Object o = ht.get(key);
- if(o == null) {
- logger = factory.makeNewLoggerInstance(name);
- logger.setHierarchy(this);
- ht.put(key, logger);
- updateParents(logger);
- return logger;
- } else if(o instanceof Logger) {
- return (Logger) o;
- } else if (o instanceof ProvisionNode) {
- //System.out.println("("+name+") ht.get(this) returned ProvisionNode");
- logger = factory.makeNewLoggerInstance(name);
- logger.setHierarchy(this);
- ht.put(key, logger);
- updateChildren((ProvisionNode) o, logger);
- updateParents(logger);
- return logger;
- }
- else {
- // It should be impossible to arrive here
- return null; // but let's keep the compiler happy.
- }
- }
- }
-
- /**
- Returns all the currently defined categories in this hierarchy as
- an {@link java.util.Enumeration Enumeration}.
-
- <p>The root logger is <em>not</em> included in the returned
- {@link Enumeration}. */
- public
- Enumeration getCurrentLoggers() {
- // The accumlation in v is necessary because not all elements in
- // ht are Logger objects as there might be some ProvisionNodes
- // as well.
- Vector v = new Vector(ht.size());
-
- Enumeration elems = ht.elements();
- while(elems.hasMoreElements()) {
- Object o = elems.nextElement();
- if(o instanceof Logger) {
- v.addElement(o);
- }
- }
- return v.elements();
- }
-
- /**
- @deprecated Please use {@link #getCurrentLoggers} instead.
- */
- public
- Enumeration getCurrentCategories() {
- return getCurrentLoggers();
- }
-
-
- /**
- Get the renderer map for this hierarchy.
- */
- public
- RendererMap getRendererMap() {
- return rendererMap;
- }
-
-
- /**
- Get the root of this hierarchy.
-
- @since 0.9.0
- */
- public
- Logger getRootLogger() {
- return root;
- }
-
- /**
- This method will return <code>true</code> if this repository is
- disabled for <code>level</code> object passed as parameter and
- <code>false</code> otherwise. See also the {@link
- #setThreshold(Level) threshold} emthod. */
- public
- boolean isDisabled(int level) {
- return thresholdInt > level;
- }
-
- /**
- @deprecated Deprecated with no replacement.
- */
- public
- void overrideAsNeeded(String override) {
- LogLog.warn("The Hiearchy.overrideAsNeeded method has been deprecated.");
- }
-
- /**
- Reset all values contained in this hierarchy instance to their
- default. This removes all appenders from all categories, sets
- the level of all non-root categories to <code>null</code>,
- sets their additivity flag to <code>true</code> and sets the level
- of the root logger to {@link Level#DEBUG DEBUG}. Moreover,
- message disabling is set its default "off" value.
-
- <p>Existing categories are not removed. They are just reset.
-
- <p>This method should be used sparingly and with care as it will
- block all logging until it is completed.</p>
-
- @since 0.8.5 */
- public
- void resetConfiguration() {
-
- getRootLogger().setLevel(Level.DEBUG);
- root.setResourceBundle(null);
- setThreshold(Level.ALL);
-
- // the synchronization is needed to prevent JDK 1.2.x hashtable
- // surprises
- synchronized(ht) {
- shutdown(); // nested locks are OK
-
- Enumeration cats = getCurrentLoggers();
- while(cats.hasMoreElements()) {
- Logger c = (Logger) cats.nextElement();
- c.setLevel(null);
- c.setAdditivity(true);
- c.setResourceBundle(null);
- }
- }
- rendererMap.clear();
- throwableRenderer = null;
- }
-
- /**
- Does nothing.
-
- @deprecated Deprecated with no replacement.
- */
- public
- void setDisableOverride(String override) {
- LogLog.warn("The Hiearchy.setDisableOverride method has been deprecated.");
- }
-
-
-
- /**
- Used by subclasses to add a renderer to the hierarchy passed as parameter.
- */
- public
- void setRenderer(Class renderedClass, ObjectRenderer renderer) {
- rendererMap.put(renderedClass, renderer);
- }
-
- /**
- * {@inheritDoc}
- */
- public void setThrowableRenderer(final ThrowableRenderer renderer) {
- throwableRenderer = renderer;
- }
-
- /**
- * {@inheritDoc}
- */
- public ThrowableRenderer getThrowableRenderer() {
- return throwableRenderer;
- }
-
-
- /**
- Shutting down a hierarchy will <em>safely</em> close and remove
- all appenders in all categories including the root logger.
-
- <p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
- and {@link AsyncAppender} need to be closed before the
- application exists. Otherwise, pending logging events might be
- lost.
-
- <p>The <code>shutdown</code> method is careful to close nested
- appenders before closing regular appenders. This is allows
- configurations where a regular appender is attached to a logger
- and again to a nested appender.
-
-
- @since 1.0 */
- public
- void shutdown() {
- Logger root = getRootLogger();
-
- // begin by closing nested appenders
- root.closeNestedAppenders();
-
- synchronized(ht) {
- Enumeration cats = this.getCurrentLoggers();
- while(cats.hasMoreElements()) {
- Logger c = (Logger) cats.nextElement();
- c.closeNestedAppenders();
- }
-
- // then, remove all appenders
- root.removeAllAppenders();
- cats = this.getCurrentLoggers();
- while(cats.hasMoreElements()) {
- Logger c = (Logger) cats.nextElement();
- c.removeAllAppenders();
- }
- }
- }
-
-
- /**
- This method loops through all the *potential* parents of
- 'cat'. There 3 possible cases:
-
- 1) No entry for the potential parent of 'cat' exists
-
- We create a ProvisionNode for this potential parent and insert
- 'cat' in that provision node.
-
- 2) There entry is of type Logger for the potential parent.
-
- The entry is 'cat's nearest existing parent. We update cat's
- parent field with this entry. We also break from the loop
- because updating our parent's parent is our parent's
- responsibility.
-
- 3) There entry is of type ProvisionNode for this potential parent.
-
- We add 'cat' to the list of children for this potential parent.
- */
- final
- private
- void updateParents(Logger cat) {
- String name = cat.name;
- int length = name.length();
- boolean parentFound = false;
-
- //System.out.println("UpdateParents called for " + name);
-
- // if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
- for(int i = name.lastIndexOf('.', length-1); i >= 0;
- i = name.lastIndexOf('.', i-1)) {
- String substr = name.substring(0, i);
-
- //System.out.println("Updating parent : " + substr);
- CategoryKey key = new CategoryKey(substr); // simple constructor
- Object o = ht.get(key);
- // Create a provision node for a future parent.
- if(o == null) {
- //System.out.println("No parent "+substr+" found. Creating ProvisionNode.");
- ProvisionNode pn = new ProvisionNode(cat);
- ht.put(key, pn);
- } else if(o instanceof Category) {
- parentFound = true;
- cat.parent = (Category) o;
- //System.out.println("Linking " + cat.name + " -> " + ((Category) o).name);
- break; // no need to update the ancestors of the closest ancestor
- } else if(o instanceof ProvisionNode) {
- ((ProvisionNode) o).addElement(cat);
- } else {
- Exception e = new IllegalStateException("unexpected object type " +
- o.getClass() + " in ht.");
- e.printStackTrace();
- }
- }
- // If we could not find any existing parents, then link with root.
- if(!parentFound) {
- cat.parent = root;
- }
- }
-
- /**
- We update the links for all the children that placed themselves
- in the provision node 'pn'. The second argument 'cat' is a
- reference for the newly created Logger, parent of all the
- children in 'pn'
-
- We loop on all the children 'c' in 'pn':
-
- If the child 'c' has been already linked to a child of
- 'cat' then there is no need to update 'c'.
-
- Otherwise, we set cat's parent field to c's parent and set
- c's parent field to cat.
-
- */
- final
- private
- void updateChildren(ProvisionNode pn, Logger logger) {
- //System.out.println("updateChildren called for " + logger.name);
- final int last = pn.size();
-
- for(int i = 0; i < last; i++) {
- Logger l = (Logger) pn.elementAt(i);
- //System.out.println("Updating child " +p.name);
-
- // Unless this child already points to a correct (lower) parent,
- // make cat.parent point to l.parent and l.parent to cat.
- if(!l.parent.name.startsWith(logger.name)) {
- logger.parent = l.parent;
- l.parent = logger;
- }
- }
- }
-
-}
-
-