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 }
208