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 Marker[] parentsSnapshot = parents;
235 if (parentsSnapshot == null) {
236 return null;
237 }
238 return Arrays.copyOf(parentsSnapshot, parentsSnapshot.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();
370 formatTo(sb);
371 return sb.toString();
372 }
373
374 @Override
375 public void formatTo(final StringBuilder sb) {
376 sb.append(name);
377 final Marker[] localParents = parents;
378 if (localParents != null) {
379 addParentInfo(sb, localParents);
380 }
381 }
382
383 @PerformanceSensitive("allocation")
384 private static void addParentInfo(final StringBuilder sb, final Marker... parents) {
385 sb.append("[ ");
386 boolean first = true;
387
388 for (int i = 0, parentsLength = parents.length; i < parentsLength; i++) {
389 final Marker marker = parents[i];
390 if (!first) {
391 sb.append(", ");
392 }
393 first = false;
394 sb.append(marker.getName());
395 final Marker[] p = marker instanceof Log4jMarker ? ((Log4jMarker) marker).parents : marker.getParents();
396 if (p != null) {
397 addParentInfo(sb, p);
398 }
399 }
400 sb.append(" ]");
401 }
402 }
403
404
405 private static void requireNonNull(final Object obj, final String message) {
406 if (obj == null) {
407 throw new IllegalArgumentException(message);
408 }
409 }
410 }