1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.message;
18
19 import java.util.Map;
20
21 import org.apache.logging.log4j.util.EnglishEnums;
22
23
24
25
26
27
28 public class StructuredDataMessage extends MapMessage {
29
30 private static final long serialVersionUID = 1703221292892071920L;
31 private static final int MAX_LENGTH = 32;
32 private static final int HASHVAL = 31;
33
34 private StructuredDataId id;
35
36 private String message;
37
38 private String type;
39
40
41
42
43 public enum Format {
44
45 XML,
46
47 FULL
48 }
49
50
51
52
53
54
55
56 public StructuredDataMessage(final String id, final String msg, final String type) {
57 this.id = new StructuredDataId(id, null, null);
58 this.message = msg;
59 this.type = type;
60 }
61
62
63
64
65
66
67
68 public StructuredDataMessage(final String id, final String msg, final String type,
69 final Map<String, String> data) {
70 super(data);
71 this.id = new StructuredDataId(id, null, null);
72 this.message = msg;
73 this.type = type;
74 }
75
76
77
78
79
80
81
82 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type) {
83 this.id = id;
84 this.message = msg;
85 this.type = type;
86 }
87
88
89
90
91
92
93
94
95 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
96 final Map<String, String> data) {
97 super(data);
98 this.id = id;
99 this.message = msg;
100 this.type = type;
101 }
102
103
104
105
106
107
108
109 private StructuredDataMessage(final StructuredDataMessage msg, final Map<String, String> map) {
110 super(map);
111 this.id = msg.id;
112 this.message = msg.message;
113 this.type = msg.type;
114 }
115
116
117
118
119
120 protected StructuredDataMessage() {
121
122 }
123
124
125
126
127
128 @Override
129 public String[] getFormats() {
130 final String[] formats = new String[Format.values().length];
131 int i = 0;
132 for (final Format format : Format.values()) {
133 formats[i++] = format.name();
134 }
135 return formats;
136 }
137
138
139
140
141
142 public StructuredDataId getId() {
143 return id;
144 }
145
146
147
148
149
150 protected void setId(final String id) {
151 this.id = new StructuredDataId(id, null, null);
152 }
153
154
155
156
157
158 protected void setId(final StructuredDataId id) {
159 this.id = id;
160 }
161
162
163
164
165
166 public String getType() {
167 return type;
168 }
169
170 protected void setType(final String type) {
171 if (type.length() > MAX_LENGTH) {
172 throw new IllegalArgumentException("structured data type exceeds maximum length of 32 characters: " + type);
173 }
174 this.type = type;
175 }
176
177
178
179
180
181 @Override
182 public String getFormat() {
183 return message;
184 }
185
186 protected void setMessageFormat(final String msg) {
187 this.message = msg;
188 }
189
190
191 @Override
192 protected void validate(final String key, final String value) {
193 validateKey(key);
194 }
195
196 private void validateKey(final String key) {
197 if (key.length() > MAX_LENGTH) {
198 throw new IllegalArgumentException("Structured data keys are limited to 32 characters. key: " + key);
199 }
200 final char[] chars = key.toCharArray();
201 for (final char c : chars) {
202 if (c < '!' || c > '~' || c == '=' || c == ']' || c == '"') {
203 throw new IllegalArgumentException("Structured data keys must contain printable US ASCII characters" +
204 "and may not contain a space, =, ], or \"");
205 }
206 }
207 }
208
209
210
211
212
213
214 @Override
215 public String asString() {
216 return asString(Format.FULL, null);
217 }
218
219
220
221
222
223
224
225
226 @Override
227 public String asString(final String format) {
228 try {
229 return asString(EnglishEnums.valueOf(Format.class, format), null);
230 } catch (final IllegalArgumentException ex) {
231 return asString();
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244 public final String asString(final Format format, final StructuredDataId structuredDataId) {
245 final StringBuilder sb = new StringBuilder();
246 final boolean full = Format.FULL.equals(format);
247 if (full) {
248 final String type = getType();
249 if (type == null) {
250 return sb.toString();
251 }
252 sb.append(getType()).append(' ');
253 }
254 StructuredDataId id = getId();
255 if (id != null) {
256 id = id.makeId(structuredDataId);
257 } else {
258 id = structuredDataId;
259 }
260 if (id == null || id.getName() == null) {
261 return sb.toString();
262 }
263 sb.append('[');
264 sb.append(id);
265 sb.append(' ');
266 appendMap(sb);
267 sb.append(']');
268 if (full) {
269 final String msg = getFormat();
270 if (msg != null) {
271 sb.append(' ').append(msg);
272 }
273 }
274 return sb.toString();
275 }
276
277
278
279
280
281 @Override
282 public String getFormattedMessage() {
283 return asString(Format.FULL, null);
284 }
285
286
287
288
289
290
291
292
293
294
295 @Override
296 public String getFormattedMessage(final String[] formats) {
297 if (formats != null && formats.length > 0) {
298 for (final String format : formats) {
299 if (Format.XML.name().equalsIgnoreCase(format)) {
300 return asXML();
301 } else if (Format.FULL.name().equalsIgnoreCase(format)) {
302 return asString(Format.FULL, null);
303 }
304 }
305 return asString(null, null);
306 }
307 return asString(Format.FULL, null);
308 }
309
310 private String asXML() {
311 final StringBuilder sb = new StringBuilder();
312 final StructuredDataId id = getId();
313 if (id == null || id.getName() == null || type == null) {
314 return sb.toString();
315 }
316 sb.append("<StructuredData>\n");
317 sb.append("<type>").append(type).append("</type>\n");
318 sb.append("<id>").append(id).append("</id>\n");
319 super.asXml(sb);
320 sb.append("</StructuredData>\n");
321 return sb.toString();
322 }
323
324 @Override
325 public String toString() {
326 return asString(null, null);
327 }
328
329
330 @Override
331 public MapMessage newInstance(final Map<String, String> map) {
332 return new StructuredDataMessage(this, map);
333 }
334
335 @Override
336 public boolean equals(final Object o) {
337 if (this == o) {
338 return true;
339 }
340 if (o == null || getClass() != o.getClass()) {
341 return false;
342 }
343
344 final StructuredDataMessage that = (StructuredDataMessage) o;
345
346 if (!super.equals(o)) {
347 return false;
348 }
349 if (type != null ? !type.equals(that.type) : that.type != null) {
350 return false;
351 }
352 if (id != null ? !id.equals(that.id) : that.id != null) {
353 return false;
354 }
355 if (message != null ? !message.equals(that.message) : that.message != null) {
356 return false;
357 }
358
359 return true;
360 }
361
362 @Override
363 public int hashCode() {
364 int result = super.hashCode();
365 result = HASHVAL * result + (type != null ? type.hashCode() : 0);
366 result = HASHVAL * result + (id != null ? id.hashCode() : 0);
367 result = HASHVAL * result + (message != null ? message.hashCode() : 0);
368 return result;
369 }
370 }