1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j;
18
19 import java.util.Arrays;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap;
22
23 import org.apache.logging.log4j.util.PerformanceSensitive;
24
25
26
27
28 public final class MarkerManager {
29
30 private static final ConcurrentMap<String, Marker> MARKERS = new ConcurrentHashMap<>();
31
32 private MarkerManager() {
33
34 }
35
36
37
38
39 public static void clear() {
40 MARKERS.clear();
41 }
42
43
44
45
46
47
48
49
50 public static boolean exists(final String key) {
51 return MARKERS.containsKey(key);
52 }
53
54
55
56
57
58
59
60
61 public static Marker getMarker(final String name) {
62 Marker result = MARKERS.get(name);
63 if (result == null) {
64 MARKERS.putIfAbsent(name, new Log4jMarker(name));
65 result = MARKERS.get(name);
66 }
67 return result;
68 }
69
70
71
72
73
74
75
76
77
78
79 @Deprecated
80 public static Marker getMarker(final String name, final String parent) {
81 final Marker parentMarker = MARKERS.get(parent);
82 if (parentMarker == null) {
83 throw new IllegalArgumentException("Parent Marker " + parent + " has not been defined");
84 }
85 @SuppressWarnings("deprecation")
86 final Marker marker = getMarker(name, parentMarker);
87 return marker;
88 }
89
90
91
92
93
94
95
96
97
98
99 @Deprecated
100 public static Marker getMarker(final String name, final Marker parent) {
101 return getMarker(name).addParents(parent);
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115 public static class Log4jMarker implements Marker {
116
117 private static final long serialVersionUID = 100L;
118
119 private final String name;
120
121 private volatile Marker[] parents;
122
123
124
125
126 @SuppressWarnings("unused")
127 private Log4jMarker() {
128 this.name = null;
129 this.parents = null;
130 }
131
132
133
134
135
136
137
138 public Log4jMarker(final String name) {
139
140
141 requireNonNull(name, "Marker name cannot be null.");
142 this.name = name;
143 this.parents = null;
144 }
145
146
147
148 @Override
149 public synchronized Marker addParents(final Marker... parentMarkers) {
150 requireNonNull(parentMarkers, "A parent marker must be specified");
151
152
153 final Marker[] localParents = this.parents;
154
155 int count = 0;
156 int size = parentMarkers.length;
157 if (localParents != null) {
158 for (final Marker parent : parentMarkers) {
159 if (!(contains(parent, localParents) || parent.isInstanceOf(this))) {
160 ++count;
161 }
162 }
163 if (count == 0) {
164 return this;
165 }
166 size = localParents.length + count;
167 }
168 final Marker[] markers = new Marker[size];
169 if (localParents != null) {
170
171
172 System.arraycopy(localParents, 0, markers, 0, localParents.length);
173 }
174 int index = localParents == null ? 0 : localParents.length;
175 for (final Marker parent : parentMarkers) {
176 if (localParents == null || !(contains(parent, localParents) || parent.isInstanceOf(this))) {
177 markers[index++] = parent;
178 }
179 }
180 this.parents = markers;
181 return this;
182 }
183
184 @Override
185 public synchronized boolean remove(final Marker parent) {
186 requireNonNull(parent, "A parent marker must be specified");
187 final Marker[] localParents = this.parents;
188 if (localParents == null) {
189 return false;
190 }
191 final int localParentsLength = localParents.length;
192 if (localParentsLength == 1) {
193 if (localParents[0].equals(parent)) {
194 parents = null;
195 return true;
196 }
197 return false;
198 }
199 int index = 0;
200 final Marker[] markers = new Marker[localParentsLength - 1];
201
202 for (int i = 0; i < localParentsLength; i++) {
203 final Marker marker = localParents[i];
204 if (!marker.equals(parent)) {
205 if (index == localParentsLength - 1) {
206
207 return false;
208 }
209 markers[index++] = marker;
210 }
211 }
212 parents = markers;
213 return true;
214 }
215
216 @Override
217 public Marker setParents(final Marker... markers) {
218 if (markers == null || markers.length == 0) {
219 this.parents = null;
220 } else {
221 final Marker[] array = new Marker[markers.length];
222 System.arraycopy(markers, 0, array, 0, markers.length);
223 this.parents = array;
224 }
225 return this;
226 }
227
228 @Override
229 public String getName() {
230 return this.name;
231 }
232
233 @Override
234 public Marker[] getParents() {
235 if (this.parents == null) {
236 return null;
237 }
238 return Arrays.copyOf(this.parents, this.parents.length);
239 }
240
241 @Override
242 public boolean hasParents() {
243 return this.parents != null;
244 }
245
246 @Override
247 @PerformanceSensitive({"allocation", "unrolled"})
248 public boolean isInstanceOf(final Marker marker) {
249 requireNonNull(marker, "A marker parameter is required");
250 if (this == marker) {
251 return true;
252 }
253 final Marker[] localParents = parents;
254 if (localParents != null) {
255
256 final int localParentsLength = localParents.length;
257 if (localParentsLength == 1) {
258 return checkParent(localParents[0], marker);
259 }
260 if (localParentsLength == 2) {
261 return checkParent(localParents[0], marker) || checkParent(localParents[1], marker);
262 }
263
264 for (int i = 0; i < localParentsLength; i++) {
265 final Marker localParent = localParents[i];
266 if (checkParent(localParent, marker)) {
267 return true;
268 }
269 }
270 }
271 return false;
272 }
273
274 @Override
275 @PerformanceSensitive({"allocation", "unrolled"})
276 public boolean isInstanceOf(final String markerName) {
277 requireNonNull(markerName, "A marker name is required");
278 if (markerName.equals(this.getName())) {
279 return true;
280 }
281
282 final Marker marker = MARKERS.get(markerName);
283 if (marker == null) {
284 return false;
285 }
286 final Marker[] localParents = parents;
287 if (localParents != null) {
288 final int localParentsLength = localParents.length;
289 if (localParentsLength == 1) {
290 return checkParent(localParents[0], marker);
291 }
292 if (localParentsLength == 2) {
293 return checkParent(localParents[0], marker) || checkParent(localParents[1], marker);
294 }
295
296 for (int i = 0; i < localParentsLength; i++) {
297 final Marker localParent = localParents[i];
298 if (checkParent(localParent, marker)) {
299 return true;
300 }
301 }
302 }
303
304 return false;
305 }
306
307 @PerformanceSensitive({"allocation", "unrolled"})
308 private static boolean checkParent(final Marker parent, final Marker marker) {
309 if (parent == marker) {
310 return true;
311 }
312 final Marker[] localParents = parent instanceof Log4jMarker ? ((Log4jMarker) parent).parents : parent
313 .getParents();
314 if (localParents != null) {
315 final int localParentsLength = localParents.length;
316 if (localParentsLength == 1) {
317 return checkParent(localParents[0], marker);
318 }
319 if (localParentsLength == 2) {
320 return checkParent(localParents[0], marker) || checkParent(localParents[1], marker);
321 }
322
323 for (int i = 0; i < localParentsLength; i++) {
324 final Marker localParent = localParents[i];
325 if (checkParent(localParent, marker)) {
326 return true;
327 }
328 }
329 }
330 return false;
331 }
332
333
334
335
336 @PerformanceSensitive("allocation")
337 private static boolean contains(final Marker parent, final Marker... localParents) {
338
339
340 for (int i = 0, localParentsLength = localParents.length; i < localParentsLength; i++) {
341 final Marker marker = localParents[i];
342 if (marker == parent) {
343 return true;
344 }
345 }
346 return false;
347 }
348
349 @Override
350 public boolean equals(final Object o) {
351 if (this == o) {
352 return true;
353 }
354 if (o == null || !(o instanceof Marker)) {
355 return false;
356 }
357 final Marker marker = (Marker) o;
358 return name.equals(marker.getName());
359 }
360
361 @Override
362 public int hashCode() {
363 return name.hashCode();
364 }
365
366 @Override
367 public String toString() {
368
369 final StringBuilder sb = new StringBuilder(name);
370 final Marker[] localParents = parents;
371 if (localParents != null) {
372 addParentInfo(sb, localParents);
373 }
374 return sb.toString();
375 }
376
377 @PerformanceSensitive("allocation")
378 private static void addParentInfo(final StringBuilder sb, final Marker... parents) {
379 sb.append("[ ");
380 boolean first = true;
381
382 for (int i = 0, parentsLength = parents.length; i < parentsLength; i++) {
383 final Marker marker = parents[i];
384 if (!first) {
385 sb.append(", ");
386 }
387 first = false;
388 sb.append(marker.getName());
389 final Marker[] p = marker instanceof Log4jMarker ? ((Log4jMarker) marker).parents : marker.getParents();
390 if (p != null) {
391 addParentInfo(sb, p);
392 }
393 }
394 sb.append(" ]");
395 }
396 }
397
398
399 private static void requireNonNull(final Object obj, final String message) {
400 if (obj == null) {
401 throw new IllegalArgumentException(message);
402 }
403 }
404 }