1
2
3
4
5
6
7
8
9
10
11
12
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 import java.util.Map;
20 import java.util.function.Supplier;
21
22 import ch.qos.logback.core.Context;
23 import ch.qos.logback.core.joran.action.Action;
24 import ch.qos.logback.core.spi.ContextAwareBase;
25 import ch.qos.logback.core.util.OptionHelper;
26
27
28
29
30
31
32
33
34 public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
35
36 static String KLEENE_STAR = "*";
37
38
39 HashMap<ElementSelector, Supplier<Action>> rules = new HashMap<>();
40
41 List<String> transparentPathParts = new ArrayList<>(2);
42 Map<String, String> pathPartsMapForRenaming = new HashMap<>(2);
43
44 public SimpleRuleStore(Context context) {
45 setContext(context);
46 }
47
48
49 public void addTransparentPathPart(String pathPart) {
50 if (pathPart == null)
51 throw new IllegalArgumentException("pathPart cannot be null");
52
53 pathPart = pathPart.trim();
54
55 if (pathPart.isEmpty())
56 throw new IllegalArgumentException("pathPart cannot be empty or to consist of only spaces");
57
58 if (pathPart.contains("/"))
59 throw new IllegalArgumentException("pathPart cannot contain '/', i.e. the forward slash character");
60
61 transparentPathParts.add(pathPart);
62
63 }
64
65
66
67
68
69
70
71
72 @Override
73 public void addPathPathMapping(String originalName, String modifiedName) {
74 pathPartsMapForRenaming.put(originalName, modifiedName);
75 }
76
77
78
79
80
81
82 public void addRule(ElementSelector elementSelector, Supplier<Action> actionSupplier) {
83
84 Supplier<Action> existing = rules.get(elementSelector);
85
86 if (existing == null) {
87 rules.put(elementSelector, actionSupplier);
88 } else {
89 throw new IllegalStateException(elementSelector.toString() + " already has an associated action supplier");
90 }
91 }
92
93 public void addRule(ElementSelector elementSelector, String actionClassName) {
94 Action action = null;
95
96 try {
97 action = (Action) OptionHelper.instantiateByClassName(actionClassName, Action.class, context);
98 } catch (Exception e) {
99 addError("Could not instantiate class [" + actionClassName + "]", e);
100 }
101 if (action != null) {
102
103 }
104 }
105
106
107
108
109
110
111
112
113 public Supplier<Action> matchActions(ElementPath elementPath) {
114
115 Supplier<Action> actionSupplier = internalMatchAction(elementPath);
116 if(actionSupplier != null) {
117 return actionSupplier;
118 }
119
120 return matchActionsWithoutTransparentPartsAndRenamedParts(elementPath);
121 }
122
123 private Supplier<Action> matchActionsWithoutTransparentPartsAndRenamedParts(ElementPath elementPath) {
124 ElementPath cleanedElementPath = removeTransparentPathParts(elementPath);
125 ElementPath renamePathParts = renamePathParts(cleanedElementPath);
126
127 return internalMatchAction(renamePathParts);
128 }
129
130
131
132
133
134
135
136
137
138
139
140 private Supplier<Action> internalMatchAction(ElementPath elementPath) {
141 Supplier<Action> actionSupplier;
142
143 if ((actionSupplier = fullPathMatch(elementPath)) != null) {
144 return actionSupplier;
145 } else if ((actionSupplier = suffixMatch(elementPath)) != null) {
146 return actionSupplier;
147 } else if ((actionSupplier = prefixMatch(elementPath)) != null) {
148 return actionSupplier;
149 } else if ((actionSupplier = middleMatch(elementPath)) != null) {
150 return actionSupplier;
151 } else {
152 return null;
153 }
154 }
155
156 ElementPath removeTransparentPathParts(ElementPath originalElementPath) {
157
158 List<String> preservedElementList = new ArrayList<>(originalElementPath.partList.size());
159
160 for (String part : originalElementPath.partList) {
161 boolean shouldKeep = transparentPathParts.stream().noneMatch(p -> p.equalsIgnoreCase(part));
162 if (shouldKeep)
163 preservedElementList.add(part);
164 }
165
166 return new ElementPath(preservedElementList);
167
168 }
169
170
171 ElementPath renamePathParts(ElementPath originalElementPath) {
172
173 List<String> result = new ArrayList<>(originalElementPath.partList.size());
174
175 for (String part : originalElementPath.partList) {
176 String modifiedName = pathPartsMapForRenaming.getOrDefault(part, part);
177 result.add(modifiedName);
178 }
179
180 return new ElementPath(result);
181 }
182
183
184 Supplier<Action> fullPathMatch(ElementPath elementPath) {
185 for (ElementSelector selector : rules.keySet()) {
186 if (selector.fullPathMatch(elementPath))
187 return rules.get(selector);
188 }
189 return null;
190 }
191
192
193 Supplier<Action> suffixMatch(ElementPath elementPath) {
194 int max = 0;
195 ElementSelector longestMatchingElementSelector = null;
196
197 for (ElementSelector selector : rules.keySet()) {
198 if (isSuffixPattern(selector)) {
199 int r = selector.getTailMatchLength(elementPath);
200 if (r > max) {
201 max = r;
202 longestMatchingElementSelector = selector;
203 }
204 }
205 }
206
207 if (longestMatchingElementSelector != null) {
208 return rules.get(longestMatchingElementSelector);
209 } else {
210 return null;
211 }
212 }
213
214 private boolean isSuffixPattern(ElementSelector p) {
215 return (p.size() > 1) && p.get(0).equals(KLEENE_STAR);
216 }
217
218 Supplier<Action> prefixMatch(ElementPath elementPath) {
219 int max = 0;
220 ElementSelector longestMatchingElementSelector = null;
221
222 for (ElementSelector selector : rules.keySet()) {
223 String last = selector.peekLast();
224 if (isKleeneStar(last)) {
225 int r = selector.getPrefixMatchLength(elementPath);
226
227 if ((r == selector.size() - 1) && (r > max)) {
228 max = r;
229 longestMatchingElementSelector = selector;
230 }
231 }
232 }
233
234 if (longestMatchingElementSelector != null) {
235 return rules.get(longestMatchingElementSelector);
236 } else {
237 return null;
238 }
239 }
240
241 private boolean isKleeneStar(String last) {
242 return KLEENE_STAR.equals(last);
243 }
244
245 Supplier<Action> middleMatch(ElementPath path) {
246
247 int max = 0;
248 ElementSelector longestMatchingElementSelector = null;
249
250 for (ElementSelector selector : rules.keySet()) {
251 String last = selector.peekLast();
252 String first = null;
253 if (selector.size() > 1) {
254 first = selector.get(0);
255 }
256 if (isKleeneStar(last) && isKleeneStar(first)) {
257 List<String> copyOfPartList = selector.getCopyOfPartList();
258 if (copyOfPartList.size() > 2) {
259 copyOfPartList.remove(0);
260 copyOfPartList.remove(copyOfPartList.size() - 1);
261 }
262
263 int r = 0;
264 ElementSelector clone = new ElementSelector(copyOfPartList);
265 if (clone.isContainedIn(path)) {
266 r = clone.size();
267 }
268 if (r > max) {
269 max = r;
270 longestMatchingElementSelector = selector;
271 }
272 }
273 }
274
275 if (longestMatchingElementSelector != null) {
276 return rules.get(longestMatchingElementSelector);
277 } else {
278 return null;
279 }
280 }
281
282 public String toString() {
283 final String TAB = " ";
284
285 StringBuilder retValue = new StringBuilder();
286
287 retValue.append("SimpleRuleStore ( ").append("rules = ").append(this.rules).append(TAB).append(" )");
288
289 return retValue.toString();
290 }
291
292 }