1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 package org.waarp.common.logging;
57
58 import org.waarp.common.utility.ParametersChecker;
59
60 import java.text.MessageFormat;
61 import java.util.HashMap;
62 import java.util.Map;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 final class MessageFormatter {
140
141 static final char DELIM_START = '{';
142 static final char DELIM_STOP = '}';
143 static final String DELIM_STR = "{}";
144 private static final char ESCAPE_CHAR = '\\';
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 static FormattingTuple format(final String messagePattern, final Object arg) {
170 return arrayFormat(messagePattern, new Object[] { arg });
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 static FormattingTuple format(final String messagePattern, final Object argA,
197 final Object argB) {
198 return arrayFormat(messagePattern, new Object[] { argA, argB });
199 }
200
201 static Throwable getThrowableCandidate(final Object[] argArray) {
202 if (argArray == null || argArray.length == 0) {
203 return null;
204 }
205
206 final Object lastEntry = argArray[argArray.length - 1];
207 if (lastEntry instanceof Throwable) {
208 return (Throwable) lastEntry;
209 }
210 return null;
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 static FormattingTuple arrayFormat(final String messagePattern,
228 final Object[] argArray) {
229
230 final Throwable throwableCandidate = getThrowableCandidate(argArray);
231
232 if (messagePattern == null) {
233 return new FormattingTuple(null, argArray, throwableCandidate);
234 }
235
236 if (argArray == null) {
237 return new FormattingTuple(messagePattern);
238 }
239
240 int i = 0;
241 int j;
242 final StringBuilder sbuild =
243 new StringBuilder(messagePattern.length() + 50);
244
245 int l;
246 for (l = 0; l < argArray.length; l++) {
247
248 j = messagePattern.indexOf(DELIM_STR, i);
249
250 if (j == -1) {
251
252 if (i == 0) {
253
254 return new FormattingTuple(messagePattern, argArray,
255 throwableCandidate);
256 } else {
257
258 sbuild.append(messagePattern.substring(i));
259 return new FormattingTuple(sbuild.toString(), argArray,
260 throwableCandidate);
261 }
262 } else {
263 if (isEscapedDelimeter(messagePattern, j)) {
264 if (!isDoubleEscaped(messagePattern, j)) {
265 l--;
266
267 sbuild.append(messagePattern, i, j - 1).append(DELIM_START);
268 i = j + 1;
269 } else {
270
271
272
273 sbuild.append(messagePattern, i, j - 1);
274 deeplyAppendParameter(sbuild, argArray[l],
275 new HashMap<Object[], Void>());
276 i = j + 2;
277 }
278 } else {
279
280 sbuild.append(messagePattern, i, j);
281 deeplyAppendParameter(sbuild, argArray[l],
282 new HashMap<Object[], Void>());
283 i = j + 2;
284 }
285 }
286 }
287
288 sbuild.append(messagePattern.substring(i));
289 if (l < argArray.length - 1) {
290 return new FormattingTuple(sbuild.toString(), argArray,
291 throwableCandidate);
292 } else {
293 return new FormattingTuple(sbuild.toString(), argArray, null);
294 }
295 }
296
297 static boolean isEscapedDelimeter(final String messagePattern,
298 final int delimeterStartIndex) {
299 ParametersChecker.checkParameterNullOnly("Must not be null",
300 messagePattern);
301 if (delimeterStartIndex == 0) {
302 return false;
303 }
304 return messagePattern.charAt(delimeterStartIndex - 1) == ESCAPE_CHAR;
305 }
306
307 static boolean isDoubleEscaped(final String messagePattern,
308 final int delimeterStartIndex) {
309 ParametersChecker.checkParameterNullOnly("Must not be null",
310 messagePattern);
311 return delimeterStartIndex >= 2 &&
312 delimeterStartIndex - 2 > messagePattern.length() &&
313 messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR;
314 }
315
316
317 static void deeplyAppendParameter(final StringBuilder sbuild, final Object o,
318 final Map<Object[], Void> seenMap) {
319 if (o == null) {
320 sbuild.append("null");
321 return;
322 }
323 if (!o.getClass().isArray()) {
324 safeObjectAppend(sbuild, o);
325 } else {
326
327
328 if (o instanceof boolean[]) {
329 booleanArrayAppend(sbuild, (boolean[]) o);
330 } else if (o instanceof byte[]) {
331 byteArrayAppend(sbuild, (byte[]) o);
332 } else if (o instanceof char[]) {
333 charArrayAppend(sbuild, (char[]) o);
334 } else if (o instanceof short[]) {
335 shortArrayAppend(sbuild, (short[]) o);
336 } else if (o instanceof int[]) {
337 intArrayAppend(sbuild, (int[]) o);
338 } else if (o instanceof long[]) {
339 longArrayAppend(sbuild, (long[]) o);
340 } else if (o instanceof float[]) {
341 floatArrayAppend(sbuild, (float[]) o);
342 } else if (o instanceof double[]) {
343 doubleArrayAppend(sbuild, (double[]) o);
344 } else {
345 objectArrayAppend(sbuild, (Object[]) o, seenMap);
346 }
347 }
348 }
349
350 private static void safeObjectAppend(final StringBuilder sbuild,
351 final Object o) {
352 try {
353 final String oAsString = o.toString();
354 sbuild.append(oAsString);
355 } catch (final Exception t) {
356 SysErrLogger.FAKE_LOGGER.ignoreLog(t);
357 SysErrLogger.FAKE_LOGGER.syserr(
358 "SLF4J: Failed toString() invocation on an object of type [" +
359 o.getClass().getName() + ']' + t.getMessage());
360 sbuild.append("[FAILED toString()]");
361 }
362 }
363
364 private static void objectArrayAppend(final StringBuilder sbuild,
365 final Object[] a,
366 final Map<Object[], Void> seenMap) {
367 sbuild.append('[');
368 if (!seenMap.containsKey(a)) {
369 seenMap.put(a, null);
370 final int len = a.length;
371 for (int i = 0; i < len; i++) {
372 deeplyAppendParameter(sbuild, a[i], seenMap);
373 if (i != len - 1) {
374 sbuild.append(", ");
375 }
376 }
377
378 seenMap.remove(a);
379 } else {
380 sbuild.append("...");
381 }
382 sbuild.append(']');
383 }
384
385 private static void booleanArrayAppend(final StringBuilder sbuild,
386 final boolean[] a) {
387 sbuild.append('[');
388 final int len = a.length;
389 for (int i = 0; i < len; i++) {
390 sbuild.append(a[i]);
391 if (i != len - 1) {
392 sbuild.append(", ");
393 }
394 }
395 sbuild.append(']');
396 }
397
398 private static void byteArrayAppend(final StringBuilder sbuild,
399 final byte[] a) {
400 sbuild.append('[');
401 final int len = a.length;
402 for (int i = 0; i < len; i++) {
403 sbuild.append(a[i]);
404 if (i != len - 1) {
405 sbuild.append(", ");
406 }
407 }
408 sbuild.append(']');
409 }
410
411 private static void charArrayAppend(final StringBuilder sbuild,
412 final char[] a) {
413 sbuild.append('[');
414 final int len = a.length;
415 for (int i = 0; i < len; i++) {
416 sbuild.append(a[i]);
417 if (i != len - 1) {
418 sbuild.append(", ");
419 }
420 }
421 sbuild.append(']');
422 }
423
424 private static void shortArrayAppend(final StringBuilder sbuild,
425 final short[] a) {
426 sbuild.append('[');
427 final int len = a.length;
428 for (int i = 0; i < len; i++) {
429 sbuild.append(a[i]);
430 if (i != len - 1) {
431 sbuild.append(", ");
432 }
433 }
434 sbuild.append(']');
435 }
436
437 private static void intArrayAppend(final StringBuilder sbuild,
438 final int[] a) {
439 sbuild.append('[');
440 final int len = a.length;
441 for (int i = 0; i < len; i++) {
442 sbuild.append(a[i]);
443 if (i != len - 1) {
444 sbuild.append(", ");
445 }
446 }
447 sbuild.append(']');
448 }
449
450 private static void longArrayAppend(final StringBuilder sbuild,
451 final long[] a) {
452 sbuild.append('[');
453 final int len = a.length;
454 for (int i = 0; i < len; i++) {
455 sbuild.append(a[i]);
456 if (i != len - 1) {
457 sbuild.append(", ");
458 }
459 }
460 sbuild.append(']');
461 }
462
463 private static void floatArrayAppend(final StringBuilder sbuild,
464 final float[] a) {
465 sbuild.append('[');
466 final int len = a.length;
467 for (int i = 0; i < len; i++) {
468 sbuild.append(a[i]);
469 if (i != len - 1) {
470 sbuild.append(", ");
471 }
472 }
473 sbuild.append(']');
474 }
475
476 private static void doubleArrayAppend(final StringBuilder sbuild,
477 final double[] a) {
478 sbuild.append('[');
479 final int len = a.length;
480 for (int i = 0; i < len; i++) {
481 sbuild.append(a[i]);
482 if (i != len - 1) {
483 sbuild.append(", ");
484 }
485 }
486 sbuild.append(']');
487 }
488
489 private MessageFormatter() {
490 }
491 }