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 <psmith@apache.org>
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 }