1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.message;
19
20 import java.util.Map;
21
22 import org.apache.logging.log4j.util.EnglishEnums;
23 import org.apache.logging.log4j.util.MultiFormatStringBuilderFormattable;
24 import org.apache.logging.log4j.util.StringBuilders;
25
26
27
28
29
30
31
32
33
34
35
36
37 @AsynchronouslyFormattable
38 public class StructuredDataMessage extends MapMessage<StructuredDataMessage, String> implements MultiFormatStringBuilderFormattable {
39
40 private static final long serialVersionUID = 1703221292892071920L;
41 private static final int MAX_LENGTH = 32;
42 private static final int HASHVAL = 31;
43
44 private StructuredDataId id;
45
46 private String message;
47
48 private String type;
49
50 private final int maxLength;
51
52
53
54
55 public enum Format {
56
57 XML,
58
59 FULL
60 }
61
62
63
64
65
66
67
68 public StructuredDataMessage(final String id, final String msg, final String type) {
69 this(id, msg, type, MAX_LENGTH);
70 }
71
72
73
74
75
76
77
78
79
80
81 public StructuredDataMessage(final String id, final String msg, final String type, final int maxLength) {
82 this.id = new StructuredDataId(id, null, null, maxLength);
83 this.message = msg;
84 this.type = type;
85 this.maxLength = maxLength;
86 }
87
88
89
90
91
92
93
94
95 public StructuredDataMessage(final String id, final String msg, final String type,
96 final Map<String, String> data) {
97 this(id, msg, type, data, MAX_LENGTH);
98 }
99
100
101
102
103
104
105
106
107
108
109
110 public StructuredDataMessage(final String id, final String msg, final String type,
111 final Map<String, String> data, final int maxLength) {
112 super(data);
113 this.id = new StructuredDataId(id, null, null, maxLength);
114 this.message = msg;
115 this.type = type;
116 this.maxLength = maxLength;
117 }
118
119
120
121
122
123
124
125 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type) {
126 this(id, msg, type, MAX_LENGTH);
127 }
128
129
130
131
132
133
134
135
136
137 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type, final int maxLength) {
138 this.id = id;
139 this.message = msg;
140 this.type = type;
141 this.maxLength = maxLength;
142 }
143
144
145
146
147
148
149
150
151
152 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
153 final Map<String, String> data) {
154 this(id, msg, type, data, MAX_LENGTH);
155 }
156
157
158
159
160
161
162
163
164
165
166
167 public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
168 final Map<String, String> data, final int maxLength) {
169 super(data);
170 this.id = id;
171 this.message = msg;
172 this.type = type;
173 this.maxLength = maxLength;
174 }
175
176
177
178
179
180
181
182 private StructuredDataMessage(final StructuredDataMessage msg, final Map<String, String> map) {
183 super(map);
184 this.id = msg.id;
185 this.message = msg.message;
186 this.type = msg.type;
187 this.maxLength = MAX_LENGTH;
188 }
189
190
191
192
193
194 protected StructuredDataMessage() {
195 maxLength = MAX_LENGTH;
196 }
197
198
199
200
201
202 @Override
203 public String[] getFormats() {
204 final String[] formats = new String[Format.values().length];
205 int i = 0;
206 for (final Format format : Format.values()) {
207 formats[i++] = format.name();
208 }
209 return formats;
210 }
211
212
213
214
215
216 public StructuredDataId getId() {
217 return id;
218 }
219
220
221
222
223
224 protected void setId(final String id) {
225 this.id = new StructuredDataId(id, null, null);
226 }
227
228
229
230
231
232 protected void setId(final StructuredDataId id) {
233 this.id = id;
234 }
235
236
237
238
239
240 public String getType() {
241 return type;
242 }
243
244 protected void setType(final String type) {
245 if (type.length() > MAX_LENGTH) {
246 throw new IllegalArgumentException("structured data type exceeds maximum length of 32 characters: " + type);
247 }
248 this.type = type;
249 }
250
251 @Override
252 public void formatTo(final StringBuilder buffer) {
253 asString(Format.FULL, null, buffer);
254 }
255
256 @Override
257 public void formatTo(String[] formats, StringBuilder buffer) {
258 asString(getFormat(formats), null, buffer);
259 }
260
261
262
263
264
265 @Override
266 public String getFormat() {
267 return message;
268 }
269
270 protected void setMessageFormat(final String msg) {
271 this.message = msg;
272 }
273
274
275
276
277
278
279 @Override
280 public String asString() {
281 return asString(Format.FULL, null);
282 }
283
284
285
286
287
288
289
290
291 @Override
292 public String asString(final String format) {
293 try {
294 return asString(EnglishEnums.valueOf(Format.class, format), null);
295 } catch (final IllegalArgumentException ex) {
296 return asString();
297 }
298 }
299
300
301
302
303
304
305
306
307
308
309 public final String asString(final Format format, final StructuredDataId structuredDataId) {
310 final StringBuilder sb = new StringBuilder();
311 asString(format, structuredDataId, sb);
312 return sb.toString();
313 }
314
315
316
317
318
319
320
321
322
323
324 public final void asString(final Format format, final StructuredDataId structuredDataId, final StringBuilder sb) {
325 final boolean full = Format.FULL.equals(format);
326 if (full) {
327 final String myType = getType();
328 if (myType == null) {
329 return;
330 }
331 sb.append(getType()).append(' ');
332 }
333 StructuredDataId sdId = getId();
334 if (sdId != null) {
335 sdId = sdId.makeId(structuredDataId);
336 } else {
337 sdId = structuredDataId;
338 }
339 if (sdId == null || sdId.getName() == null) {
340 return;
341 }
342 if (Format.XML.equals(format)) {
343 asXml(sdId, sb);
344 return;
345 }
346 sb.append('[');
347 StringBuilders.appendValue(sb, sdId);
348 sb.append(' ');
349 appendMap(sb);
350 sb.append(']');
351 if (full) {
352 final String msg = getFormat();
353 if (msg != null) {
354 sb.append(' ').append(msg);
355 }
356 }
357 }
358
359 private void asXml(StructuredDataId structuredDataId, StringBuilder sb) {
360 sb.append("<StructuredData>\n");
361 sb.append("<type>").append(type).append("</type>\n");
362 sb.append("<id>").append(structuredDataId).append("</id>\n");
363 super.asXml(sb);
364 sb.append("\n</StructuredData>\n");
365 }
366
367
368
369
370
371 @Override
372 public String getFormattedMessage() {
373 return asString(Format.FULL, null);
374 }
375
376
377
378
379
380
381
382
383
384
385 @Override
386 public String getFormattedMessage(final String[] formats) {
387 return asString(getFormat(formats), null);
388 }
389
390 private Format getFormat(String[] formats) {
391 if (formats != null && formats.length > 0) {
392 for (int i = 0; i < formats.length; i++) {
393 final String format = formats[i];
394 if (Format.XML.name().equalsIgnoreCase(format)) {
395 return Format.XML;
396 } else if (Format.FULL.name().equalsIgnoreCase(format)) {
397 return Format.FULL;
398 }
399 }
400 return null;
401 }
402 return Format.FULL;
403 }
404
405 @Override
406 public String toString() {
407 return asString(null, null);
408 }
409
410
411 @Override
412 public StructuredDataMessage newInstance(final Map<String, String> map) {
413 return new StructuredDataMessage(this, map);
414 }
415
416 @Override
417 public boolean equals(final Object o) {
418 if (this == o) {
419 return true;
420 }
421 if (o == null || getClass() != o.getClass()) {
422 return false;
423 }
424
425 final StructuredDataMessage that = (StructuredDataMessage) o;
426
427 if (!super.equals(o)) {
428 return false;
429 }
430 if (type != null ? !type.equals(that.type) : that.type != null) {
431 return false;
432 }
433 if (id != null ? !id.equals(that.id) : that.id != null) {
434 return false;
435 }
436 if (message != null ? !message.equals(that.message) : that.message != null) {
437 return false;
438 }
439
440 return true;
441 }
442
443 @Override
444 public int hashCode() {
445 int result = super.hashCode();
446 result = HASHVAL * result + (type != null ? type.hashCode() : 0);
447 result = HASHVAL * result + (id != null ? id.hashCode() : 0);
448 result = HASHVAL * result + (message != null ? message.hashCode() : 0);
449 return result;
450 }
451
452 @Override
453 protected void validate(final String key, final boolean value) {
454 validateKey(key);
455 }
456
457
458
459
460 @Override
461 protected void validate(final String key, final byte value) {
462 validateKey(key);
463 }
464
465
466
467
468 @Override
469 protected void validate(final String key, final char value) {
470 validateKey(key);
471 }
472
473
474
475
476 @Override
477 protected void validate(final String key, final double value) {
478 validateKey(key);
479 }
480
481
482
483
484 @Override
485 protected void validate(final String key, final float value) {
486 validateKey(key);
487 }
488
489
490
491
492 @Override
493 protected void validate(final String key, final int value) {
494 validateKey(key);
495 }
496
497
498
499
500 @Override
501 protected void validate(final String key, final long value) {
502 validateKey(key);
503 }
504
505
506
507
508 @Override
509 protected void validate(final String key, final Object value) {
510 validateKey(key);
511 }
512
513
514
515
516 @Override
517 protected void validate(final String key, final short value) {
518 validateKey(key);
519 }
520
521 @Override
522 protected void validate(final String key, final String value) {
523 validateKey(key);
524 }
525
526 protected void validateKey(final String key) {
527 if (maxLength > 0 && key.length() > maxLength) {
528 throw new IllegalArgumentException("Structured data keys are limited to " + maxLength +
529 " characters. key: " + key);
530 }
531 for (int i = 0; i < key.length(); i++) {
532 final char c = key.charAt(i);
533 if (c < '!' || c > '~' || c == '=' || c == ']' || c == '"') {
534 throw new IllegalArgumentException("Structured data keys must contain printable US ASCII characters" +
535 "and may not contain a space, =, ], or \"");
536 }
537 }
538 }
539
540 }