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.StringBuilderFormattable;
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 StringBuilderFormattable {
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
257
258
259
260 @Override
261 public String getFormat() {
262 return message;
263 }
264
265 protected void setMessageFormat(final String msg) {
266 this.message = msg;
267 }
268
269
270
271
272
273
274 @Override
275 public String asString() {
276 return asString(Format.FULL, null);
277 }
278
279
280
281
282
283
284
285
286 @Override
287 public String asString(final String format) {
288 try {
289 return asString(EnglishEnums.valueOf(Format.class, format), null);
290 } catch (final IllegalArgumentException ex) {
291 return asString();
292 }
293 }
294
295
296
297
298
299
300
301
302
303
304 public final String asString(final Format format, final StructuredDataId structuredDataId) {
305 final StringBuilder sb = new StringBuilder();
306 asString(format, structuredDataId, sb);
307 return sb.toString();
308 }
309
310
311
312
313
314
315
316
317
318
319 public final void asString(final Format format, final StructuredDataId structuredDataId, final StringBuilder sb) {
320 final boolean full = Format.FULL.equals(format);
321 if (full) {
322 final String myType = getType();
323 if (myType == null) {
324 return;
325 }
326 sb.append(getType()).append(' ');
327 }
328 StructuredDataId sdId = getId();
329 if (sdId != null) {
330 sdId = sdId.makeId(structuredDataId);
331 } else {
332 sdId = structuredDataId;
333 }
334 if (sdId == null || sdId.getName() == null) {
335 return;
336 }
337 sb.append('[');
338 StringBuilders.appendValue(sb, sdId);
339 sb.append(' ');
340 appendMap(sb);
341 sb.append(']');
342 if (full) {
343 final String msg = getFormat();
344 if (msg != null) {
345 sb.append(' ').append(msg);
346 }
347 }
348 }
349
350
351
352
353
354 @Override
355 public String getFormattedMessage() {
356 return asString(Format.FULL, null);
357 }
358
359
360
361
362
363
364
365
366
367
368 @Override
369 public String getFormattedMessage(final String[] formats) {
370 if (formats != null && formats.length > 0) {
371 for (int i = 0; i < formats.length; i++) {
372 final String format = formats[i];
373 if (Format.XML.name().equalsIgnoreCase(format)) {
374 return asXml();
375 } else if (Format.FULL.name().equalsIgnoreCase(format)) {
376 return asString(Format.FULL, null);
377 }
378 }
379 return asString(null, null);
380 }
381 return asString(Format.FULL, null);
382 }
383
384 private String asXml() {
385 final StringBuilder sb = new StringBuilder();
386 final StructuredDataId sdId = getId();
387 if (sdId == null || sdId.getName() == null || type == null) {
388 return sb.toString();
389 }
390 sb.append("<StructuredData>\n");
391 sb.append("<type>").append(type).append("</type>\n");
392 sb.append("<id>").append(sdId).append("</id>\n");
393 super.asXml(sb);
394 sb.append("</StructuredData>\n");
395 return sb.toString();
396 }
397
398 @Override
399 public String toString() {
400 return asString(null, null);
401 }
402
403
404 @Override
405 public StructuredDataMessage newInstance(final Map<String, String> map) {
406 return new StructuredDataMessage(this, map);
407 }
408
409 @Override
410 public boolean equals(final Object o) {
411 if (this == o) {
412 return true;
413 }
414 if (o == null || getClass() != o.getClass()) {
415 return false;
416 }
417
418 final StructuredDataMessage that = (StructuredDataMessage) o;
419
420 if (!super.equals(o)) {
421 return false;
422 }
423 if (type != null ? !type.equals(that.type) : that.type != null) {
424 return false;
425 }
426 if (id != null ? !id.equals(that.id) : that.id != null) {
427 return false;
428 }
429 if (message != null ? !message.equals(that.message) : that.message != null) {
430 return false;
431 }
432
433 return true;
434 }
435
436 @Override
437 public int hashCode() {
438 int result = super.hashCode();
439 result = HASHVAL * result + (type != null ? type.hashCode() : 0);
440 result = HASHVAL * result + (id != null ? id.hashCode() : 0);
441 result = HASHVAL * result + (message != null ? message.hashCode() : 0);
442 return result;
443 }
444
445 @Override
446 protected void validate(final String key, final boolean value) {
447 validateKey(key);
448 }
449
450
451
452
453 @Override
454 protected void validate(final String key, final byte value) {
455 validateKey(key);
456 }
457
458
459
460
461 @Override
462 protected void validate(final String key, final char value) {
463 validateKey(key);
464 }
465
466
467
468
469 @Override
470 protected void validate(final String key, final double value) {
471 validateKey(key);
472 }
473
474
475
476
477 @Override
478 protected void validate(final String key, final float value) {
479 validateKey(key);
480 }
481
482
483
484
485 @Override
486 protected void validate(final String key, final int value) {
487 validateKey(key);
488 }
489
490
491
492
493 @Override
494 protected void validate(final String key, final long value) {
495 validateKey(key);
496 }
497
498
499
500
501 @Override
502 protected void validate(final String key, final Object value) {
503 validateKey(key);
504 }
505
506
507
508
509 @Override
510 protected void validate(final String key, final short value) {
511 validateKey(key);
512 }
513
514 @Override
515 protected void validate(final String key, final String value) {
516 validateKey(key);
517 }
518
519 protected void validateKey(final String key) {
520 if (maxLength > 0 && key.length() > maxLength) {
521 throw new IllegalArgumentException("Structured data keys are limited to " + maxLength +
522 " characters. key: " + key);
523 }
524 for (int i = 0; i < key.length(); i++) {
525 final char c = key.charAt(i);
526 if (c < '!' || c > '~' || c == '=' || c == ']' || c == '"') {
527 throw new IllegalArgumentException("Structured data keys must contain printable US ASCII characters" +
528 "and may not contain a space, =, ], or \"");
529 }
530 }
531 }
532
533 }