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