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.StringBuilders;
24
25
26
27
28
29
30
31
32
33
34
35
36 @AsynchronouslyFormattable
37 public class StructuredDataMessage extends MapMessage<StructuredDataMessage, String> {
38
39 private static final long serialVersionUID = 1703221292892071920L;
40 private static final int MAX_LENGTH = 32;
41 private static final int HASHVAL = 31;
42
43 private StructuredDataId id;
44
45 private String message;
46
47 private String type;
48
49 private final int maxLength;
50
51
52
53
54 public enum Format {
55
56 XML,
57
58 FULL
59 }
60
61
62
63
64
65
66
67 public StructuredDataMessage(final String id, final String msg, final String type) {
68 this(id, msg, type, MAX_LENGTH);
69 }
70
71
72
73
74
75
76
77
78
79
80 public StructuredDataMessage(final String id, final String msg, final String type, final int maxLength) {
81 this.id = new StructuredDataId(id, null, null, maxLength);
82 this.message = msg;
83 this.type = type;
84 this.maxLength = maxLength;
85 }
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 protected StructuredDataMessage() {
194 maxLength = MAX_LENGTH;
195 }
196
197
198
199
200
201 @Override
202 public String[] getFormats() {
203 final String[] formats = new String[Format.values().length];
204 int i = 0;
205 for (final Format format : Format.values()) {
206 formats[i++] = format.name();
207 }
208 return formats;
209 }
210
211
212
213
214
215 public StructuredDataId getId() {
216 return id;
217 }
218
219
220
221
222
223 protected void setId(final String id) {
224 this.id = new StructuredDataId(id, null, null);
225 }
226
227
228
229
230
231 protected void setId(final StructuredDataId id) {
232 this.id = id;
233 }
234
235
236
237
238
239 public String getType() {
240 return type;
241 }
242
243 protected void setType(final String type) {
244 if (type.length() > MAX_LENGTH) {
245 throw new IllegalArgumentException("structured data type exceeds maximum length of 32 characters: " + type);
246 }
247 this.type = type;
248 }
249
250 @Override
251 public void formatTo(final StringBuilder buffer) {
252 asString(Format.FULL, null, buffer);
253 }
254
255 @Override
256 public void formatTo(final String[] formats, final StringBuilder buffer) {
257 asString(getFormat(formats), null, buffer);
258 }
259
260
261
262
263
264 @Override
265 public String getFormat() {
266 return message;
267 }
268
269 protected void setMessageFormat(final String msg) {
270 this.message = msg;
271 }
272
273
274
275
276
277
278 @Override
279 public String asString() {
280 return asString(Format.FULL, null);
281 }
282
283
284
285
286
287
288
289
290 @Override
291 public String asString(final String format) {
292 try {
293 return asString(EnglishEnums.valueOf(Format.class, format), null);
294 } catch (final IllegalArgumentException ex) {
295 return asString();
296 }
297 }
298
299
300
301
302
303
304
305
306
307
308 public final String asString(final Format format, final StructuredDataId structuredDataId) {
309 final StringBuilder sb = new StringBuilder();
310 asString(format, structuredDataId, sb);
311 return sb.toString();
312 }
313
314
315
316
317
318
319
320
321
322
323 public final void asString(final Format format, final StructuredDataId structuredDataId, final StringBuilder sb) {
324 final boolean full = Format.FULL.equals(format);
325 if (full) {
326 final String myType = getType();
327 if (myType == null) {
328 return;
329 }
330 sb.append(getType()).append(' ');
331 }
332 StructuredDataId sdId = getId();
333 if (sdId != null) {
334 sdId = sdId.makeId(structuredDataId);
335 } else {
336 sdId = structuredDataId;
337 }
338 if (sdId == null || sdId.getName() == null) {
339 return;
340 }
341 if (Format.XML.equals(format)) {
342 asXml(sdId, sb);
343 return;
344 }
345 sb.append('[');
346 StringBuilders.appendValue(sb, sdId);
347 sb.append(' ');
348 appendMap(sb);
349 sb.append(']');
350 if (full) {
351 final String msg = getFormat();
352 if (msg != null) {
353 sb.append(' ').append(msg);
354 }
355 }
356 }
357
358 private void asXml(final StructuredDataId structuredDataId, final StringBuilder sb) {
359 sb.append("<StructuredData>\n");
360 sb.append("<type>").append(type).append("</type>\n");
361 sb.append("<id>").append(structuredDataId).append("</id>\n");
362 super.asXml(sb);
363 sb.append("\n</StructuredData>\n");
364 }
365
366
367
368
369
370 @Override
371 public String getFormattedMessage() {
372 return asString(Format.FULL, null);
373 }
374
375
376
377
378
379
380
381
382
383
384 @Override
385 public String getFormattedMessage(final String[] formats) {
386 return asString(getFormat(formats), null);
387 }
388
389 private Format getFormat(final String[] formats) {
390 if (formats != null && formats.length > 0) {
391 for (int i = 0; i < formats.length; i++) {
392 final String format = formats[i];
393 if (Format.XML.name().equalsIgnoreCase(format)) {
394 return Format.XML;
395 } else if (Format.FULL.name().equalsIgnoreCase(format)) {
396 return Format.FULL;
397 }
398 }
399 return null;
400 }
401 return Format.FULL;
402 }
403
404 @Override
405 public String toString() {
406 return asString(null, null);
407 }
408
409
410 @Override
411 public StructuredDataMessage newInstance(final Map<String, String> map) {
412 return new StructuredDataMessage(this, map);
413 }
414
415 @Override
416 public boolean equals(final Object o) {
417 if (this == o) {
418 return true;
419 }
420 if (o == null || getClass() != o.getClass()) {
421 return false;
422 }
423
424 final StructuredDataMessage that = (StructuredDataMessage) o;
425
426 if (!super.equals(o)) {
427 return false;
428 }
429 if (type != null ? !type.equals(that.type) : that.type != null) {
430 return false;
431 }
432 if (id != null ? !id.equals(that.id) : that.id != null) {
433 return false;
434 }
435 if (message != null ? !message.equals(that.message) : that.message != null) {
436 return false;
437 }
438
439 return true;
440 }
441
442 @Override
443 public int hashCode() {
444 int result = super.hashCode();
445 result = HASHVAL * result + (type != null ? type.hashCode() : 0);
446 result = HASHVAL * result + (id != null ? id.hashCode() : 0);
447 result = HASHVAL * result + (message != null ? message.hashCode() : 0);
448 return result;
449 }
450
451 @Override
452 protected void validate(final String key, final boolean value) {
453 validateKey(key);
454 }
455
456
457
458
459 @Override
460 protected void validate(final String key, final byte value) {
461 validateKey(key);
462 }
463
464
465
466
467 @Override
468 protected void validate(final String key, final char value) {
469 validateKey(key);
470 }
471
472
473
474
475 @Override
476 protected void validate(final String key, final double value) {
477 validateKey(key);
478 }
479
480
481
482
483 @Override
484 protected void validate(final String key, final float value) {
485 validateKey(key);
486 }
487
488
489
490
491 @Override
492 protected void validate(final String key, final int value) {
493 validateKey(key);
494 }
495
496
497
498
499 @Override
500 protected void validate(final String key, final long value) {
501 validateKey(key);
502 }
503
504
505
506
507 @Override
508 protected void validate(final String key, final Object value) {
509 validateKey(key);
510 }
511
512
513
514
515 @Override
516 protected void validate(final String key, final short value) {
517 validateKey(key);
518 }
519
520 @Override
521 protected void validate(final String key, final String value) {
522 validateKey(key);
523 }
524
525 protected void validateKey(final String key) {
526 if (maxLength > 0 && key.length() > maxLength) {
527 throw new IllegalArgumentException("Structured data keys are limited to " + maxLength +
528 " characters. key: " + key);
529 }
530 for (int i = 0; i < key.length(); i++) {
531 final char c = key.charAt(i);
532 if (c < '!' || c > '~' || c == '=' || c == ']' || c == '"') {
533 throw new IllegalArgumentException("Structured data keys must contain printable US ASCII characters" +
534 "and may not contain a space, =, ], or \"");
535 }
536 }
537 }
538
539 }