1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.core.model.processor;
16
17 import ch.qos.logback.core.Context;
18 import ch.qos.logback.core.FileAppender;
19 import ch.qos.logback.core.model.AppenderModel;
20 import ch.qos.logback.core.model.ImplicitModel;
21 import ch.qos.logback.core.model.Model;
22 import ch.qos.logback.core.rolling.RollingFileAppender;
23 import ch.qos.logback.core.rolling.helper.FileNamePattern;
24
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.function.Supplier;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32
33 @PhaseIndicator(phase = ProcessingPhase.DEPENDENCY_ANALYSIS)
34 public class FileCollisionAnalyser extends ModelHandlerBase {
35
36 public FileCollisionAnalyser(Context context) {
37 super(context);
38 }
39
40 @Override
41 protected Class<AppenderModel> getSupportedModelClass() {
42 return AppenderModel.class;
43 }
44
45
46 @Override
47 public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
48 AppenderModel appenderModel = (AppenderModel) model;
49
50 String originalClassName = appenderModel.getClassName();
51 String className = mic.getImport(originalClassName);
52
53 String appenderName = appenderModel.getName();
54
55 if (!fileAppenderOrRollingFileAppender(className)) {
56 return;
57 }
58
59 String tagName0 = "file";
60 checkForCollisions(mic, MapKey.FILE_COLLISION_MAP_KEY, appenderModel, appenderName, tagName0);
61
62 String tagName1 = "fileNamePattern";
63 checkForCollisions(mic, MapKey.RFA_FILENAME_COLLISION_MAP, appenderModel, appenderName, tagName1);
64 }
65
66 private static boolean fileAppenderOrRollingFileAppender(String className) {
67 return FileAppender.class.getName().equals(className) || RollingFileAppender.class.getName().equals(className);
68 }
69
70
71 boolean tagPredicate(Model model, String tagName) {
72 return (model instanceof ImplicitModel) && tagName.equals(model.getTag());
73 }
74
75 enum MapKey {
76 FILE_COLLISION_MAP_KEY, RFA_FILENAME_COLLISION_MAP
77 }
78
79 private void checkForCollisions(ModelInterpretationContext mic, MapKey mapKey, AppenderModel appenderModel, String appenderName, final String tagName) {
80
81
82 Stream<Model> streamLevel1 = appenderModel.getSubModels().stream();
83 Stream<Model> streamLevel2 = appenderModel.getSubModels().stream().flatMap(child -> child.getSubModels().stream());
84
85 List<Model> matchingModels = Stream.concat(streamLevel1, streamLevel2).filter(m -> tagPredicate(m, tagName)).collect(Collectors.toList());
86
87
88
89 if(!matchingModels.isEmpty()) {
90 ImplicitModel implicitModel = (ImplicitModel) matchingModels.get(0);
91 String bodyValue = mic.subst(implicitModel.getBodyText());
92
93
94 Map<String, String> faileCollisionMap = getCollisionMapByKey(mic, mapKey);
95
96 Optional<Map.Entry<String, String>> collision = faileCollisionMap.entrySet()
97 .stream()
98 .filter(entry -> bodyValue.equals(entry.getValue()))
99 .findFirst();
100
101 if (collision.isPresent()) {
102 addErrorForCollision(tagName, appenderName, collision.get().getKey(), bodyValue);
103 appenderModel.markAsHandled();
104 appenderModel.deepMarkAsSkipped();
105 } else {
106
107
108 faileCollisionMap.put(appenderName, bodyValue);
109 }
110 }
111 }
112
113 private Map<String, String> getCollisionMapByKey(ModelInterpretationContext mic, MapKey mapKey) {
114 Map<String, String> map = (Map<String, String>) mic.getObjectMap().get(mapKey.name());
115 if(map == null) {
116 map = new HashMap<>();
117 mic.getObjectMap().put(mapKey.name(), map);
118 }
119 return map;
120 }
121
122
123 static public final String COLLISION_DETECTED = "Collision detected. Skipping initialization of appender named [%s]";
124 static public final String COLLISION_MESSAGE = "In appender [%s] option '%s' has the same value '%s' as that set for appender [%s] defined earlier";
125 private void addErrorForCollision(String optionName, String appenderName, String previousAppenderName, String optionValue) {
126 addError(String.format(COLLISION_DETECTED, appenderName));
127 addError(String.format(COLLISION_MESSAGE, appenderName, optionName, optionValue, previousAppenderName));
128 }
129 }