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  package org.apache.log4j.chainsaw.color;
19  
20  import java.awt.Color;
21  import java.beans.PropertyChangeListener;
22  import java.beans.PropertyChangeSupport;
23  import java.io.BufferedInputStream;
24  import java.io.BufferedOutputStream;
25  import java.io.EOFException;
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.io.FileNotFoundException;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.ObjectInputStream;
32  import java.io.ObjectOutputStream;
33  import java.net.URLEncoder;
34  import java.util.ArrayList;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Vector;
40  
41  import org.apache.log4j.chainsaw.ChainsawConstants;
42  import org.apache.log4j.chainsaw.prefs.SettingsManager;
43  import org.apache.log4j.rule.ColorRule;
44  import org.apache.log4j.rule.ExpressionRule;
45  import org.apache.log4j.rule.Rule;
46  import org.apache.log4j.spi.LoggingEvent;
47  
48  
49  /**
50   * A colorizer supporting an ordered collection of ColorRules, including support for notification of
51   * color rule changes via a propertyChangeListener and the 'colorrule' property.
52   *
53   * @author Scott Deboy <sdeboy@apache.org>
54   */
55  public class RuleColorizer implements Colorizer {
56    private Map rules;
57    private final PropertyChangeSupport colorChangeSupport =
58      new PropertyChangeSupport(this);
59    private Map defaultRules = new HashMap();
60    private String currentRuleSet = ChainsawConstants.DEFAULT_COLOR_RULE_NAME;
61    private Rule findRule;
62    private Rule loggerRule;
63  
64    private static final String COLORS_EXTENSION = ".colors";
65  
66    private final Color WARN_DEFAULT_COLOR = new Color(255, 255, 153);
67    private final Color FATAL_OR_ERROR_DEFAULT_COLOR = new Color(255, 153, 153);
68    private final Color MARKER_DEFAULT_COLOR = new Color(153, 255, 153);
69  
70    private final String DEFAULT_WARN_EXPRESSION = "level == WARN";
71    private final String DEFAULT_FATAL_ERROR_EXCEPTION_EXPRESSION = "level == FATAL || level == ERROR || exception exists";
72    private final String DEFAULT_MARKER_EXPRESSION = "prop.marker exists";
73  
74    public RuleColorizer() {
75      List rulesList = new ArrayList();
76  
77        String expression = DEFAULT_FATAL_ERROR_EXCEPTION_EXPRESSION;
78        rulesList.add(
79        new ColorRule(
80          expression, ExpressionRule.getRule(expression), FATAL_OR_ERROR_DEFAULT_COLOR,
81          Color.black));
82        expression = DEFAULT_WARN_EXPRESSION;
83        rulesList.add(
84        new ColorRule(
85          expression, ExpressionRule.getRule(expression), WARN_DEFAULT_COLOR,
86          Color.black));
87  
88        expression = DEFAULT_MARKER_EXPRESSION;
89        rulesList.add(
90          new ColorRule(
91            expression, ExpressionRule.getRule(expression), MARKER_DEFAULT_COLOR,
92            Color.black));
93  
94      defaultRules.put(currentRuleSet, rulesList);
95      setRules(defaultRules);
96    }
97  
98    public void setLoggerRule(Rule loggerRule) {
99      this.loggerRule = loggerRule;
100     colorChangeSupport.firePropertyChange("colorrule", false, true);
101   }
102 
103   public void setFindRule(Rule findRule) {
104     this.findRule = findRule;
105     colorChangeSupport.firePropertyChange("colorrule", false, true);
106   }
107 
108   public Rule getFindRule() {
109     return findRule;
110   }
111 
112   public Rule getLoggerRule() {
113     return loggerRule;
114   }
115 
116   public void setRules(Map rules) {
117     this.rules = rules;
118     colorChangeSupport.firePropertyChange("colorrule", false, true);
119   }
120   
121   public Map getRules() {
122     return rules;
123   }
124 
125   public List getCurrentRules() {
126     return (List) rules.get(currentRuleSet);
127   }
128 
129   public void addRules(Map newRules) {
130     Iterator iter = newRules.entrySet().iterator();
131 
132     while (iter.hasNext()) {
133       Map.Entry entry = (Map.Entry) iter.next();
134 
135       if (rules.containsKey(entry.getKey())) {
136         ((List) rules.get(entry.getKey())).addAll((List) entry.getValue());
137       } else {
138         rules.put(entry.getKey(), entry.getValue());
139       }
140     }
141 
142     colorChangeSupport.firePropertyChange("colorrule", false, true);
143   }
144 
145   public void addRule(String ruleSetName, ColorRule rule) {
146     if (rules.containsKey(ruleSetName)) {
147       ((List) rules.get(ruleSetName)).add(rule);
148     } else {
149       List list = new ArrayList();
150       list.add(rule);
151       rules.put(ruleSetName, list);
152     }
153 
154     colorChangeSupport.firePropertyChange("colorrule", false, true);
155   }
156 
157   public void removeRule(String ruleSetName, String expression) {
158     if (rules.containsKey(ruleSetName)) {
159       List list = (List) rules.get(ruleSetName);
160 
161       for (int i = 0; i < list.size(); i++) {
162         ColorRule rule = (ColorRule) list.get(i);
163 
164         if (rule.getExpression().equals(expression)) {
165           list.remove(rule);
166 
167           return;
168         }
169       }
170     }
171   }
172 
173   public void setCurrentRuleSet(String ruleSetName) {
174     currentRuleSet = ruleSetName;
175   }
176 
177   public Color getBackgroundColor(LoggingEvent event) {
178     if (rules.containsKey(currentRuleSet)) {
179       List list = (List) rules.get(currentRuleSet);
180       Iterator iter = list.iterator();
181 
182       while (iter.hasNext()) {
183         ColorRule rule = (ColorRule) iter.next();
184 
185         if ((rule.getBackgroundColor() != null) && (rule.evaluate(event, null))) {
186           return rule.getBackgroundColor();
187         }
188       }
189     }
190 
191     return null;
192   }
193 
194   public Color getForegroundColor(LoggingEvent event) {
195     if (rules.containsKey(currentRuleSet)) {
196       List list = (List) rules.get(currentRuleSet);
197       Iterator iter = list.iterator();
198 
199       while (iter.hasNext()) {
200         ColorRule rule = (ColorRule) iter.next();
201 
202         if ((rule.getForegroundColor() != null) && (rule.evaluate(event, null))) {
203           return rule.getForegroundColor();
204         }
205       }
206     }
207 
208     return null;
209   }
210   
211   public void addPropertyChangeListener(PropertyChangeListener listener) {
212     colorChangeSupport.addPropertyChangeListener(listener);
213   }
214 
215   public void removePropertyChangeListener(PropertyChangeListener listener) {
216     colorChangeSupport.removePropertyChangeListener(listener);
217   }
218 
219   /**
220    * @param propertyName
221    * @param listener
222    */
223   public void addPropertyChangeListener(
224     String propertyName, PropertyChangeListener listener) {
225     colorChangeSupport.addPropertyChangeListener(propertyName, listener);
226   }
227 
228 
229     /**
230      * Save panel color settings
231      */
232     public void saveColorSettings(String name) {
233       ObjectOutputStream o = null;
234       try {
235         File f = new File(SettingsManager.getInstance().getSettingsDirectory(), URLEncoder.encode(name + COLORS_EXTENSION));
236 
237         o = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
238 
239         o.writeObject(getRules());
240         o.flush();
241       } catch (FileNotFoundException fnfe) {
242         fnfe.printStackTrace();
243       } catch (IOException ioe) {
244         ioe.printStackTrace();
245       } finally {
246         try {
247           if (o != null) {
248             o.close();
249           }
250         } catch (IOException ioe) {
251           ioe.printStackTrace();
252         }
253       }
254     }
255 
256   /**
257    * Load panel color settings if they exist - otherwise, load default color settings
258    */
259   public void loadColorSettings(String name) {
260     if (!doLoadColorSettings(name)) {
261       doLoadColorSettings(ChainsawConstants.DEFAULT_COLOR_RULE_NAME);
262     }
263   }
264 
265   private boolean doLoadColorSettings(String name) {
266     //first attempt to load encoded file
267     File f = new File(SettingsManager.getInstance().getSettingsDirectory(), URLEncoder.encode(name) + COLORS_EXTENSION);
268 
269     if (f.exists()) {
270       ObjectInputStream s = null;
271 
272       try {
273         s = new ObjectInputStream(
274             new BufferedInputStream(new FileInputStream(f)));
275 
276         Map map = (Map) s.readObject();
277         setRules(map);
278       } catch (EOFException eof) { //end of file - ignore..
279       }catch (IOException ioe) {
280         ioe.printStackTrace();
281         //unable to load file - delete it
282         f.delete();
283       } catch (ClassNotFoundException cnfe) {
284         cnfe.printStackTrace();
285       } finally {
286         if (s != null) {
287           try {
288             s.close();
289           } catch (IOException ioe) {
290             ioe.printStackTrace();
291           }
292         }
293       }
294     }
295     return f.exists();
296   }
297 
298     public Vector getDefaultColors() {
299       Vector vec = new Vector();
300 
301       vec.add(Color.white);
302       vec.add(Color.black);
303       //add default alternating color & search backgrounds (both foreground are black)
304       vec.add(ChainsawConstants.COLOR_ODD_ROW_BACKGROUND);
305       vec.add(ChainsawConstants.FIND_LOGGER_BACKGROUND);
306 
307       vec.add(new Color(255, 255, 225));
308       vec.add(new Color(255, 225, 255));
309       vec.add(new Color(225, 255, 255));
310       vec.add(new Color(255, 225, 225));
311       vec.add(new Color(225, 255, 225));
312       vec.add(new Color(225, 225, 255));
313       vec.add(new Color(225, 225, 183));
314       vec.add(new Color(225, 183, 225));
315       vec.add(new Color(183, 225, 225));
316       vec.add(new Color(183, 225, 183));
317       vec.add(new Color(183, 183, 225));
318       vec.add(new Color(232, 201, 169));
319       vec.add(new Color(255, 255, 153));
320       vec.add(new Color(255, 153, 153));
321       vec.add(new Color(189, 156, 89));
322       vec.add(new Color(255, 102, 102));
323       vec.add(new Color(255, 177, 61));
324       vec.add(new Color(61, 255, 61));
325       vec.add(new Color(153, 153, 255));
326       vec.add(new Color(255, 153, 255));
327 
328       return vec;
329     }
330 
331 }