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