View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.joran.spi;
15  
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.List;
19  
20  import ch.qos.logback.core.Context;
21  import ch.qos.logback.core.joran.action.Action;
22  import ch.qos.logback.core.spi.ContextAwareBase;
23  import ch.qos.logback.core.util.OptionHelper;
24  
25  /**
26   * This class implements the {@link RuleStore} interface. It is the rule store
27   * implementation used by default in Joran.
28   * 
29   * @author Ceki Gülcü
30   * 
31   */
32  public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
33  
34      static String KLEENE_STAR = "*";
35  
36      // key: Pattern instance, value: ArrayList containing actions
37      HashMap<ElementSelector, List<Action>> rules = new HashMap<ElementSelector, List<Action>>();
38  
39      // public SimpleRuleStore() {
40      // }
41  
42      public SimpleRuleStore(Context context) {
43          setContext(context);
44      }
45  
46      /**
47       * Add a new rule, i.e. a pattern, action pair to the rule store. <p> Note
48       * that the added action's LoggerRepository will be set in the process.
49       */
50      public void addRule(ElementSelector elementSelector, Action action) {
51          action.setContext(context);
52  
53          List<Action> a4p = rules.get(elementSelector);
54  
55          if (a4p == null) {
56              a4p = new ArrayList<Action>();
57              rules.put(elementSelector, a4p);
58          }
59  
60          a4p.add(action);
61      }
62  
63      public void addRule(ElementSelector elementSelector, String actionClassName) {
64          Action action = null;
65  
66          try {
67              action = (Action) OptionHelper.instantiateByClassName(actionClassName, Action.class, context);
68          } catch (Exception e) {
69              addError("Could not instantiate class [" + actionClassName + "]", e);
70          }
71          if (action != null) {
72              addRule(elementSelector, action);
73          }
74      }
75  
76      // exact match has highest priority
77      // if no exact match, check for suffix (tail) match, i.e matches
78      // of type */x/y. Suffix match for */x/y has higher priority than match for
79      // */x
80      // if no suffix match, check for prefix match, i.e. matches for x/*
81      // match for x/y/* has higher priority than matches for x/*
82  
83      public List<Action> matchActions(ElementPath elementPath) {
84          List<Action> actionList;
85  
86          if ((actionList = fullPathMatch(elementPath)) != null) {
87              return actionList;
88          } else if ((actionList = suffixMatch(elementPath)) != null) {
89              return actionList;
90          } else if ((actionList = prefixMatch(elementPath)) != null) {
91              return actionList;
92          } else if ((actionList = middleMatch(elementPath)) != null) {
93              return actionList;
94          } else {
95              return null;
96          }
97      }
98  
99      List<Action> fullPathMatch(ElementPath elementPath) {
100         for (ElementSelector selector : rules.keySet()) {
101             if (selector.fullPathMatch(elementPath))
102                 return rules.get(selector);
103         }
104         return null;
105     }
106 
107     // Suffix matches are matches of type */x/y
108     List<Action> suffixMatch(ElementPath elementPath) {
109         int max = 0;
110         ElementSelector longestMatchingElementSelector = null;
111 
112         for (ElementSelector selector : rules.keySet()) {
113             if (isSuffixPattern(selector)) {
114                 int r = selector.getTailMatchLength(elementPath);
115                 if (r > max) {
116                     max = r;
117                     longestMatchingElementSelector = selector;
118                 }
119             }
120         }
121 
122         if (longestMatchingElementSelector != null) {
123             return rules.get(longestMatchingElementSelector);
124         } else {
125             return null;
126         }
127     }
128 
129     private boolean isSuffixPattern(ElementSelector p) {
130         return (p.size() > 1) && p.get(0).equals(KLEENE_STAR);
131     }
132 
133     List<Action> prefixMatch(ElementPath elementPath) {
134         int max = 0;
135         ElementSelector longestMatchingElementSelector = null;
136 
137         for (ElementSelector selector : rules.keySet()) {
138             String last = selector.peekLast();
139             if (isKleeneStar(last)) {
140                 int r = selector.getPrefixMatchLength(elementPath);
141                 // to qualify the match length must equal p's size omitting the '*'
142                 if ((r == selector.size() - 1) && (r > max)) {
143                     max = r;
144                     longestMatchingElementSelector = selector;
145                 }
146             }
147         }
148 
149         if (longestMatchingElementSelector != null) {
150             return rules.get(longestMatchingElementSelector);
151         } else {
152             return null;
153         }
154     }
155 
156     private boolean isKleeneStar(String last) {
157         return KLEENE_STAR.equals(last);
158     }
159 
160     List<Action> middleMatch(ElementPath path) {
161 
162         int max = 0;
163         ElementSelector longestMatchingElementSelector = null;
164 
165         for (ElementSelector selector : rules.keySet()) {
166             String last = selector.peekLast();
167             String first = null;
168             if (selector.size() > 1) {
169                 first = selector.get(0);
170             }
171             if (isKleeneStar(last) && isKleeneStar(first)) {
172                 List<String> copyOfPartList = selector.getCopyOfPartList();
173                 if (copyOfPartList.size() > 2) {
174                     copyOfPartList.remove(0);
175                     copyOfPartList.remove(copyOfPartList.size() - 1);
176                 }
177 
178                 int r = 0;
179                 ElementSelector clone = new ElementSelector(copyOfPartList);
180                 if (clone.isContainedIn(path)) {
181                     r = clone.size();
182                 }
183                 if (r > max) {
184                     max = r;
185                     longestMatchingElementSelector = selector;
186                 }
187             }
188         }
189 
190         if (longestMatchingElementSelector != null) {
191             return rules.get(longestMatchingElementSelector);
192         } else {
193             return null;
194         }
195     }
196 
197     public String toString() {
198         final String TAB = "  ";
199 
200         StringBuilder retValue = new StringBuilder();
201 
202         retValue.append("SimpleRuleStore ( ").append("rules = ").append(this.rules).append(TAB).append(" )");
203 
204         return retValue.toString();
205     }
206 
207 }