001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.log4j.lf5.viewer.configure;
018
019import java.awt.Color;
020import java.io.File;
021import java.io.FileWriter;
022import java.io.IOException;
023import java.io.PrintWriter;
024import java.util.ArrayList;
025import java.util.Enumeration;
026import java.util.Iterator;
027import java.util.List;
028import java.util.Map;
029
030import javax.swing.JCheckBoxMenuItem;
031import javax.swing.tree.TreePath;
032import javax.xml.parsers.DocumentBuilder;
033import javax.xml.parsers.DocumentBuilderFactory;
034
035import org.apache.log4j.lf5.LogLevel;
036import org.apache.log4j.lf5.LogLevelFormatException;
037import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
038import org.apache.log4j.lf5.viewer.LogTable;
039import org.apache.log4j.lf5.viewer.LogTableColumn;
040import org.apache.log4j.lf5.viewer.LogTableColumnFormatException;
041import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerModel;
042import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerTree;
043import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryNode;
044import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryPath;
045import org.w3c.dom.Document;
046import org.w3c.dom.NamedNodeMap;
047import org.w3c.dom.Node;
048import org.w3c.dom.NodeList;
049
050/**
051 * <p>ConfigurationManager handles the storage and retrival of the state of
052 * the CategoryExplorer
053 *
054 * @author Richard Hurst
055 * @author Brad Marlborough
056 */
057
058// Contributed by ThoughtWorks Inc.
059
060public class ConfigurationManager extends Object {
061  //--------------------------------------------------------------------------
062  //   Constants:
063  //--------------------------------------------------------------------------
064  private static final String CONFIG_FILE_NAME = "lf5_configuration.xml";
065  private static final String NAME = "name";
066  private static final String PATH = "path";
067  private static final String SELECTED = "selected";
068  private static final String EXPANDED = "expanded";
069  private static final String CATEGORY = "category";
070  private static final String FIRST_CATEGORY_NAME = "Categories";
071  private static final String LEVEL = "level";
072  private static final String COLORLEVEL = "colorlevel";
073  private static final String RED = "red";
074  private static final String GREEN = "green";
075  private static final String BLUE = "blue";
076  private static final String COLUMN = "column";
077  private static final String NDCTEXTFILTER = "searchtext";
078  //--------------------------------------------------------------------------
079  //   Protected Variables:
080  //--------------------------------------------------------------------------
081
082  //--------------------------------------------------------------------------
083  //   Private Variables:
084  //--------------------------------------------------------------------------
085  private LogBrokerMonitor _monitor = null;
086  private LogTable _table = null;
087
088  //--------------------------------------------------------------------------
089  //   Constructors:
090  //--------------------------------------------------------------------------
091  public ConfigurationManager(LogBrokerMonitor monitor, LogTable table) {
092    super();
093    _monitor = monitor;
094    _table = table;
095    load();
096  }
097  //--------------------------------------------------------------------------
098  //   Public Methods:
099  //--------------------------------------------------------------------------
100
101  public void save() {
102    CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
103    CategoryNode root = model.getRootCategoryNode();
104
105    StringBuffer xml = new StringBuffer(2048);
106    openXMLDocument(xml);
107    openConfigurationXML(xml);
108    processLogRecordFilter(_monitor.getNDCTextFilter(), xml);
109    processLogLevels(_monitor.getLogLevelMenuItems(), xml);
110    processLogLevelColors(_monitor.getLogLevelMenuItems(),
111        LogLevel.getLogLevelColorMap(), xml);
112    processLogTableColumns(LogTableColumn.getLogTableColumns(), xml);
113    processConfigurationNode(root, xml);
114    closeConfigurationXML(xml);
115    store(xml.toString());
116  }
117
118  public void reset() {
119    deleteConfigurationFile();
120    collapseTree();
121    selectAllNodes();
122  }
123
124  public static String treePathToString(TreePath path) {
125    // count begins at one so as to not include the 'Categories' - root category
126    StringBuffer sb = new StringBuffer();
127    CategoryNode n = null;
128    Object[] objects = path.getPath();
129    for (int i = 1; i < objects.length; i++) {
130      n = (CategoryNode) objects[i];
131      if (i > 1) {
132        sb.append(".");
133      }
134      sb.append(n.getTitle());
135    }
136    return sb.toString();
137  }
138
139  //--------------------------------------------------------------------------
140  //   Protected Methods:
141  //--------------------------------------------------------------------------
142  protected void load() {
143    File file = new File(getFilename());
144    if (file.exists()) {
145      try {
146        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.
147            newInstance();
148        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
149        Document doc = docBuilder.parse(file);
150        processRecordFilter(doc);
151        processCategories(doc);
152        processLogLevels(doc);
153        processLogLevelColors(doc);
154        processLogTableColumns(doc);
155      } catch (Exception e) {
156        // ignore all error and just continue as if there was no
157        // configuration xml file but do report a message
158        System.err.println("Unable process configuration file at " +
159            getFilename() + ". Error Message=" + e.getMessage());
160      }
161    }
162
163  }
164
165  // Added in version 1.2 - reads in the NDC text filter from the
166  // xml configuration file.  If the value of the filter is not null
167  // or an empty string ("") then the manager will set the LogBrokerMonitor's
168  // LogRecordFilter to use the NDC LogRecordFilter.  Otherwise, the
169  // LogBrokerMonitor will use the default LogRecordFilter.
170  protected void processRecordFilter(Document doc) {
171    NodeList nodeList = doc.getElementsByTagName(NDCTEXTFILTER);
172
173    // there is only one value stored
174    Node n = nodeList.item(0);
175    // add check for backwards compatibility  as this feature was added in
176    // version 1.2
177    if (n == null) {
178      return;
179    }
180
181    NamedNodeMap map = n.getAttributes();
182    String text = getValue(map, NAME);
183
184    if (text == null || text.equals("")) {
185      return;
186    }
187    _monitor.setNDCLogRecordFilter(text);
188  }
189
190  protected void processCategories(Document doc) {
191    CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
192    CategoryExplorerModel model = tree.getExplorerModel();
193    NodeList nodeList = doc.getElementsByTagName(CATEGORY);
194
195    // determine where the starting node is
196    NamedNodeMap map = nodeList.item(0).getAttributes();
197    int j = (getValue(map, NAME).equalsIgnoreCase(FIRST_CATEGORY_NAME)) ? 1 : 0;
198    // iterate backwards throught the nodeList so that expansion of the
199    // list can occur
200    for (int i = nodeList.getLength() - 1; i >= j; i--) {
201      Node n = nodeList.item(i);
202      map = n.getAttributes();
203      CategoryNode chnode = model.addCategory(new CategoryPath(getValue(map, PATH)));
204      chnode.setSelected((getValue(map, SELECTED).equalsIgnoreCase("true")) ? true : false);
205      if (getValue(map, EXPANDED).equalsIgnoreCase("true")) ;
206      tree.expandPath(model.getTreePathToRoot(chnode));
207    }
208
209  }
210
211  protected void processLogLevels(Document doc) {
212    NodeList nodeList = doc.getElementsByTagName(LEVEL);
213    Map menuItems = _monitor.getLogLevelMenuItems();
214
215    for (int i = 0; i < nodeList.getLength(); i++) {
216      Node n = nodeList.item(i);
217      NamedNodeMap map = n.getAttributes();
218      String name = getValue(map, NAME);
219      try {
220        JCheckBoxMenuItem item =
221            (JCheckBoxMenuItem) menuItems.get(LogLevel.valueOf(name));
222        item.setSelected(getValue(map, SELECTED).equalsIgnoreCase("true"));
223      } catch (LogLevelFormatException e) {
224        // ignore it will be on by default.
225      }
226    }
227  }
228
229  protected void processLogLevelColors(Document doc) {
230    NodeList nodeList = doc.getElementsByTagName(COLORLEVEL);
231    LogLevel.getLogLevelColorMap();
232
233    for (int i = 0; i < nodeList.getLength(); i++) {
234      Node n = nodeList.item(i);
235      // check for backwards compatibility since this feature was added
236      // in version 1.3
237      if (n == null) {
238        return;
239      }
240
241      NamedNodeMap map = n.getAttributes();
242      String name = getValue(map, NAME);
243      try {
244        LogLevel level = LogLevel.valueOf(name);
245        int red = Integer.parseInt(getValue(map, RED));
246        int green = Integer.parseInt(getValue(map, GREEN));
247        int blue = Integer.parseInt(getValue(map, BLUE));
248        Color c = new Color(red, green, blue);
249        if (level != null) {
250          level.setLogLevelColorMap(level, c);
251        }
252
253      } catch (LogLevelFormatException e) {
254        // ignore it will be on by default.
255      }
256    }
257  }
258
259  protected void processLogTableColumns(Document doc) {
260    NodeList nodeList = doc.getElementsByTagName(COLUMN);
261    Map menuItems = _monitor.getLogTableColumnMenuItems();
262    List selectedColumns = new ArrayList();
263    for (int i = 0; i < nodeList.getLength(); i++) {
264      Node n = nodeList.item(i);
265      // check for backwards compatibility since this feature was added
266      // in version 1.3
267      if (n == null) {
268        return;
269      }
270      NamedNodeMap map = n.getAttributes();
271      String name = getValue(map, NAME);
272      try {
273        LogTableColumn column = LogTableColumn.valueOf(name);
274        JCheckBoxMenuItem item =
275            (JCheckBoxMenuItem) menuItems.get(column);
276        item.setSelected(getValue(map, SELECTED).equalsIgnoreCase("true"));
277
278        if (item.isSelected()) {
279          selectedColumns.add(column);
280        }
281      } catch (LogTableColumnFormatException e) {
282        // ignore it will be on by default.
283      }
284
285      if (selectedColumns.isEmpty()) {
286        _table.setDetailedView();
287      } else {
288        _table.setView(selectedColumns);
289      }
290
291    }
292  }
293
294  protected String getValue(NamedNodeMap map, String attr) {
295    Node n = map.getNamedItem(attr);
296    return n.getNodeValue();
297  }
298
299  protected void collapseTree() {
300    // collapse everything except the first category
301    CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
302    for (int i = tree.getRowCount() - 1; i > 0; i--) {
303      tree.collapseRow(i);
304    }
305  }
306
307  protected void selectAllNodes() {
308    CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
309    CategoryNode root = model.getRootCategoryNode();
310    Enumeration all = root.breadthFirstEnumeration();
311    CategoryNode n = null;
312    while (all.hasMoreElements()) {
313      n = (CategoryNode) all.nextElement();
314      n.setSelected(true);
315    }
316  }
317
318  protected void store(String s) {
319
320    try {
321      PrintWriter writer = new PrintWriter(new FileWriter(getFilename()));
322      writer.print(s);
323      writer.close();
324    } catch (IOException e) {
325      // do something with this error.
326      e.printStackTrace();
327    }
328
329  }
330
331  protected void deleteConfigurationFile() {
332    try {
333      File f = new File(getFilename());
334      if (f.exists()) {
335        f.delete();
336      }
337    } catch (SecurityException e) {
338      System.err.println("Cannot delete " + getFilename() +
339          " because a security violation occured.");
340    }
341  }
342
343  protected String getFilename() {
344    String home = System.getProperty("user.home");
345    String sep = System.getProperty("file.separator");
346
347    return home + sep + "lf5" + sep + CONFIG_FILE_NAME;
348  }
349
350  //--------------------------------------------------------------------------
351  //   Private Methods:
352  //--------------------------------------------------------------------------
353  private void processConfigurationNode(CategoryNode node, StringBuffer xml) {
354    CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
355
356    Enumeration all = node.breadthFirstEnumeration();
357    CategoryNode n = null;
358    while (all.hasMoreElements()) {
359      n = (CategoryNode) all.nextElement();
360      exportXMLElement(n, model.getTreePathToRoot(n), xml);
361    }
362
363  }
364
365  private void processLogLevels(Map logLevelMenuItems, StringBuffer xml) {
366    xml.append("\t<loglevels>\r\n");
367    Iterator it = logLevelMenuItems.keySet().iterator();
368    while (it.hasNext()) {
369      LogLevel level = (LogLevel) it.next();
370      JCheckBoxMenuItem item = (JCheckBoxMenuItem) logLevelMenuItems.get(level);
371      exportLogLevelXMLElement(level.getLabel(), item.isSelected(), xml);
372    }
373
374    xml.append("\t</loglevels>\r\n");
375  }
376
377  private void processLogLevelColors(Map logLevelMenuItems, Map logLevelColors, StringBuffer xml) {
378    xml.append("\t<loglevelcolors>\r\n");
379    // iterate through the list of log levels being used (log4j, jdk1.4, custom levels)
380    Iterator it = logLevelMenuItems.keySet().iterator();
381    while (it.hasNext()) {
382      LogLevel level = (LogLevel) it.next();
383      // for each level, get the associated color from the log level color map
384      Color color = (Color) logLevelColors.get(level);
385      exportLogLevelColorXMLElement(level.getLabel(), color, xml);
386    }
387
388    xml.append("\t</loglevelcolors>\r\n");
389  }
390
391
392  private void processLogTableColumns(List logTableColumnMenuItems, StringBuffer xml) {
393    xml.append("\t<logtablecolumns>\r\n");
394    Iterator it = logTableColumnMenuItems.iterator();
395    while (it.hasNext()) {
396      LogTableColumn column = (LogTableColumn) it.next();
397      JCheckBoxMenuItem item = _monitor.getTableColumnMenuItem(column);
398      exportLogTableColumnXMLElement(column.getLabel(), item.isSelected(), xml);
399    }
400
401    xml.append("\t</logtablecolumns>\r\n");
402  }
403
404  // Added in version 1.2 - stores the NDC text filter in the xml file
405  // for future use.
406  private void processLogRecordFilter(String text, StringBuffer xml) {
407    xml.append("\t<").append(NDCTEXTFILTER).append(" ");
408    xml.append(NAME).append("=\"").append(text).append("\"");
409    xml.append("/>\r\n");
410  }
411
412  private void openXMLDocument(StringBuffer xml) {
413    xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
414  }
415
416  private void openConfigurationXML(StringBuffer xml) {
417    xml.append("<configuration>\r\n");
418  }
419
420  private void closeConfigurationXML(StringBuffer xml) {
421    xml.append("</configuration>\r\n");
422  }
423
424  private void exportXMLElement(CategoryNode node, TreePath path, StringBuffer xml) {
425    CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
426
427    xml.append("\t<").append(CATEGORY).append(" ");
428    xml.append(NAME).append("=\"").append(node.getTitle()).append("\" ");
429    xml.append(PATH).append("=\"").append(treePathToString(path)).append("\" ");
430    xml.append(EXPANDED).append("=\"").append(tree.isExpanded(path)).append("\" ");
431    xml.append(SELECTED).append("=\"").append(node.isSelected()).append("\"/>\r\n");
432  }
433
434  private void exportLogLevelXMLElement(String label, boolean selected, StringBuffer xml) {
435    xml.append("\t\t<").append(LEVEL).append(" ").append(NAME);
436    xml.append("=\"").append(label).append("\" ");
437    xml.append(SELECTED).append("=\"").append(selected);
438    xml.append("\"/>\r\n");
439  }
440
441  private void exportLogLevelColorXMLElement(String label, Color color, StringBuffer xml) {
442    xml.append("\t\t<").append(COLORLEVEL).append(" ").append(NAME);
443    xml.append("=\"").append(label).append("\" ");
444    xml.append(RED).append("=\"").append(color.getRed()).append("\" ");
445    xml.append(GREEN).append("=\"").append(color.getGreen()).append("\" ");
446    xml.append(BLUE).append("=\"").append(color.getBlue());
447    xml.append("\"/>\r\n");
448  }
449
450  private void exportLogTableColumnXMLElement(String label, boolean selected, StringBuffer xml) {
451    xml.append("\t\t<").append(COLUMN).append(" ").append(NAME);
452    xml.append("=\"").append(label).append("\" ");
453    xml.append(SELECTED).append("=\"").append(selected);
454    xml.append("\"/>\r\n");
455  }
456  //--------------------------------------------------------------------------
457  //   Nested Top-Level Classes or Interfaces:
458  //--------------------------------------------------------------------------
459
460}
461
462
463
464
465
466