Merge branch 'develop' into feature/JAL-3551Pymol
[jalview.git] / srcjar_unused / org / apache / log4j / Hierarchy.java
diff --git a/srcjar_unused/org/apache/log4j/Hierarchy.java b/srcjar_unused/org/apache/log4j/Hierarchy.java
new file mode 100644 (file)
index 0000000..6c82c98
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * 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&uuml;lc&uuml;
+
+*/
+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;
+      }
+    }
+  }
+
+}
+
+