1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.audit.request;
18
19 import java.lang.annotation.Annotation;
20 import java.lang.reflect.Field;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.function.Supplier;
24
25 import org.apache.logging.log4j.audit.annotation.Chained;
26 import org.apache.logging.log4j.audit.annotation.ChainedSupplier;
27 import org.apache.logging.log4j.audit.annotation.ClientServer;
28 import org.apache.logging.log4j.audit.annotation.HeaderPrefix;
29 import org.apache.logging.log4j.audit.annotation.Local;
30
31 public class RequestContextMappings {
32
33 private static final String DEFAULT_HEADER_PREFIX = "request-context-";
34 private final Map<String, RequestContextMapping> mappings = new HashMap<>();
35 private final String headerPrefix;
36
37 public RequestContextMappings(String fqcn) {
38 this(getClass(fqcn));
39 }
40
41 private static Class<?> getClass(String fqcn) {
42 if (fqcn == null) {
43 throw new IllegalArgumentException("RequestContext class name cannot be null");
44 }
45 try {
46 return Class.forName(fqcn);
47 } catch (ClassNotFoundException ex) {
48 throw new IllegalArgumentException("Invalid RequestContext class name", ex);
49 }
50 }
51
52 public RequestContextMappings(Class<?> clazz) {
53 if (clazz == null) {
54 throw new IllegalArgumentException("A RequestContext class must be provided");
55 }
56 Annotation annotation = clazz.getAnnotation(HeaderPrefix.class);
57 this.headerPrefix = annotation != null ? ((HeaderPrefix) annotation).value().toLowerCase() : DEFAULT_HEADER_PREFIX;
58 Field[] fields = clazz.getDeclaredFields();
59 for (Field field : fields) {
60 if (field.getType().equals(String.class)) {
61 String fieldName;
62 try {
63 fieldName = (String) field.get(null);
64 } catch (IllegalAccessException ex) {
65 continue;
66 }
67 if (fieldName == null) {
68 continue;
69 }
70 annotation = field.getAnnotation(ClientServer.class);
71 if (annotation != null) {
72 mappings.put(fieldName.toLowerCase(), new ClientServerMapping(fieldName));
73 continue;
74 }
75
76 annotation = field.getAnnotation(Local.class);
77 if (annotation != null) {
78 mappings.put(fieldName.toLowerCase(), new LocalMapping(fieldName));
79 }
80 } else if (field.getType().equals(Supplier.class)) {
81 annotation = field.getAnnotation(Chained.class);
82 if (annotation != null) {
83 Chained chained = (Chained) annotation;
84 try {
85 @SuppressWarnings("unchecked")
86 Supplier<String> supplier = (Supplier<String>) field.get(null);
87 mappings.put(chained.fieldName().toLowerCase(),
88 new ChainedMapping(chained.fieldName(), chained.chainedFieldName(), supplier));
89 } catch (IllegalAccessException ex) {
90 throw new IllegalArgumentException("Unable to retrieve Supplier for chained field " + chained.fieldName());
91 }
92 }
93 }
94 }
95 mappings.entrySet().removeIf(a -> validateChained(a.getValue()));
96 }
97
98 public RequestContextMapping getMapping(String name) {
99 return mappings.get(name.toLowerCase());
100 }
101
102 public RequestContextMapping getMappingByHeader(String header) {
103 String hdr = header.toLowerCase();
104 if (hdr.startsWith(headerPrefix)) {
105 return mappings.get(hdr.substring(headerPrefix.length()));
106 }
107 return null;
108 }
109
110 public String getHeaderPrefix() {
111 return headerPrefix;
112 }
113
114 private boolean validateChained(RequestContextMapping mapping) {
115 return mapping.getScope() == Scope.CHAIN && !mappings.containsKey(mapping.getChainKey().toLowerCase());
116 }
117 }