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
    18  /*
    19   */
    20  package org.apache.log4j.chainsaw;
    21
    22  import org.apache.log4j.LogManager;
    23  import org.apache.log4j.Logger;
    24
    25  import javax.swing.*;
    26  import javax.swing.tree.DefaultMutableTreeNode;
    27  import javax.swing.tree.DefaultTreeModel;
    28  import javax.swing.tree.MutableTreeNode;
    29  import java.util.*;
    30
    31
    32  /**
    33   * A TreeModel that represents the Loggers for a given LogPanel
    34   *
    35   * @author Paul Smith &lt;psmith@apache.org&gt;
    36   */
    37  class LogPanelLoggerTreeModel extends DefaultTreeModel
    38      implements LoggerNameListener {
    39      private Map<String, LogPanelTreeNode> fullPackageMap = new HashMap<>();
    40      private final Logger logger = LogManager.getLogger(LogPanelLoggerTreeModel.class);
    41
    42      LogPanelLoggerTreeModel() {
    43          super(new LogPanelTreeNode("Root Logger"));
    44      }
    45
    46      /* (non-Javadoc)
    47       * @see org.apache.log4j.chainsaw.LoggerNameListener#loggerNameAdded(java.lang.String)
    48       */
    49      public void loggerNameAdded(final String loggerName) {
    50          //invoke later, not on current EDT
    51          SwingUtilities.invokeLater(
    52              () -> addLoggerNameInDispatchThread(loggerName));
    53      }
    54
    55      public void reset() {
    56          DefaultMutableTreeNode current = (DefaultMutableTreeNode) getRoot();
    57          current.removeAllChildren();
    58          fullPackageMap.clear();
    59          nodeStructureChanged(current);
    60      }
    61
    62      private void addLoggerNameInDispatchThread(final String loggerName) {
    63          String[] packages = tokenize(loggerName);
    64
    65          /**
    66           * The packages array is effectively the tree
    67           * path that must exist within the tree, so
    68           * we walk the tree ensuring each level is present
    69           */
    70          DefaultMutableTreeNode current = (DefaultMutableTreeNode) getRoot();
    71
    72
    73  /**
    74   * This label is used to break out when descending the
    75   * current tree hierachy, and it has matched a package name
    76   * with an already existing TreeNode.
    77   */
    78          outerFor:
    79          for (int i = 0; i < packages.length; i++) {
    80              String packageName = packages[i];
    81              Enumeration enumeration = current.children();
    82
    83              while (enumeration.hasMoreElements()) {
    84                  DefaultMutableTreeNode child =
    85                      (DefaultMutableTreeNode) enumeration.nextElement();
    86                  String childName = child.getUserObject().toString();
    87
    88                  if (childName.equals(packageName)) {
    89                      /**
    90                       * This the current known branch to descend
    91                       */
    92                      current = child;
    93
    94                      /**
    95                       * we've found it, so break back to the outer
    96                       * for loop to continue processing further
    97                       * down the tree
    98                       */
    99                      continue outerFor;
    100                 }
    101             }
    102
    103             /*
    104              * So we haven't found this index in the current children,
    105              * better create the child
    106              */
    107             final LogPanelTreeNode newChild = new LogPanelTreeNode(packageName);
    108
    109             StringBuilder fullPackageBuf = new StringBuilder();
    110
    111             for (int j = 0; j <= i; j++) {
    112                 fullPackageBuf.append(packages[j]);
    113
    114                 if (j < i) {
    115                     fullPackageBuf.append(".");
    116                 }
    117             }
    118
    119             logger.debug("Adding to Map " + fullPackageBuf.toString());
    120             fullPackageMap.put(fullPackageBuf.toString(), newChild);
    121
    122             final DefaultMutableTreeNode changedNode = current;
    123
    124             changedNode.add(newChild);
    125
    126             final int[] changedIndices = new int[changedNode.getChildCount()];
    127
    128             for (int j = 0; j < changedIndices.length; j++) {
    129                 changedIndices[j] = j;
    130             }
    131
    132             nodesWereInserted(
    133                 changedNode, new int[]{changedNode.getIndex(newChild)});
    134             nodesChanged(changedNode, changedIndices);
    135             current = newChild;
    136         }
    137     }
    138
    139     LogPanelTreeNode lookupLogger(String newLogger) {
    140         if (fullPackageMap.containsKey(newLogger)) {
    141             return fullPackageMap.get(newLogger);
    142         } else {
    143             logger.debug("No logger found matching '" + newLogger + "'");
    144             logger.debug("Map Dump: " + fullPackageMap);
    145         }
    146
    147         return null;
    148     }
    149
    150     /**
    151      * Takes the loggerName and tokenizes it into it's
    152      * package name lements returning the elements
    153      * via the Stirng[]
    154      *
    155      * @param loggerName
    156      * @return array of strings representing the package hierarchy
    157      */
    158     private String[] tokenize(String loggerName) {
    159         StringTokenizer tok = new StringTokenizer(loggerName, ".");
    160
    161         String[] tokens = new String[tok.countTokens()];
    162
    163         int index = 0;
    164
    165         while (tok.hasMoreTokens()) {
    166             tokens[index++] = tok.nextToken();
    167         }
    168
    169         return tokens;
    170     }
    171
    172     private static class LogPanelTreeNode extends DefaultMutableTreeNode {
    173         protected static Comparator nodeComparator =
    174             (o1, o2) -> o1.toString().compareToIgnoreCase(o2.toString());
    175
    176         private LogPanelTreeNode(String logName) {
    177             super(logName);
    178         }
    179
    180         public void insert(MutableTreeNode newChild, int childIndex) {
    181             //      logger.debug("[" + this.getUserObject() + "] inserting child " + newChild + " @ index " + childIndex);
    182             //      logger.debug("Children now: " + this.children);
    183             super.insert(newChild, childIndex);
    184
    185             //	  logger.debug("Children after insert: " + this.children);
    186             this.children.sort(nodeComparator);
    187
    188             //	  logger.debug("Children after sort: " + this.children);
    189         }
    190     }
    191 }