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 package org.slf4j.helpers;
26
27 import java.text.MessageFormat;
28 import java.util.HashMap;
29 import java.util.Map;
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
57
58
59
60
61
62
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 final public class MessageFormatter {
99 static final char DELIM_START = '{';
100 static final char DELIM_STOP = '}';
101 static final String DELIM_STR = "{}";
102 private static final char ESCAPE_CHAR = '\\';
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 final public static FormattingTuple format(String messagePattern, Object arg) {
124 return arrayFormat(messagePattern, new Object[] { arg });
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 final public static FormattingTuple format(final String messagePattern,
151 Object arg1, Object arg2) {
152 return arrayFormat(messagePattern, new Object[] { arg1, arg2 });
153 }
154
155 static final Throwable getThrowableCandidate(Object[] argArray) {
156 if (argArray == null || argArray.length == 0) {
157 return null;
158 }
159
160 final Object lastEntry = argArray[argArray.length - 1];
161 if (lastEntry instanceof Throwable) {
162 return (Throwable) lastEntry;
163 }
164 return null;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179 final public static FormattingTuple arrayFormat(final String messagePattern,
180 final Object[] argArray) {
181
182 Throwable throwableCandidate = getThrowableCandidate(argArray);
183
184 if (messagePattern == null) {
185 return new FormattingTuple(null, argArray, throwableCandidate);
186 }
187
188 if (argArray == null) {
189 return new FormattingTuple(messagePattern);
190 }
191
192 int i = 0;
193 int j;
194 StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);
195
196 int L;
197 for (L = 0; L < argArray.length; L++) {
198
199 j = messagePattern.indexOf(DELIM_STR, i);
200
201 if (j == -1) {
202
203 if (i == 0) {
204 return new FormattingTuple(messagePattern, argArray,
205 throwableCandidate);
206 } else {
207
208 sbuf.append(messagePattern.substring(i, messagePattern.length()));
209 return new FormattingTuple(sbuf.toString(), argArray,
210 throwableCandidate);
211 }
212 } else {
213 if (isEscapedDelimeter(messagePattern, j)) {
214 if (!isDoubleEscaped(messagePattern, j)) {
215 L--;
216 sbuf.append(messagePattern.substring(i, j - 1));
217 sbuf.append(DELIM_START);
218 i = j + 1;
219 } else {
220
221
222
223 sbuf.append(messagePattern.substring(i, j - 1));
224 deeplyAppendParameter(sbuf, argArray[L], new HashMap());
225 i = j + 2;
226 }
227 } else {
228
229 sbuf.append(messagePattern.substring(i, j));
230 deeplyAppendParameter(sbuf, argArray[L], new HashMap());
231 i = j + 2;
232 }
233 }
234 }
235
236 sbuf.append(messagePattern.substring(i, messagePattern.length()));
237 if (L < argArray.length - 1) {
238 return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate);
239 } else {
240 return new FormattingTuple(sbuf.toString(), argArray, null);
241 }
242 }
243
244 final static boolean isEscapedDelimeter(String messagePattern,
245 int delimeterStartIndex) {
246
247 if (delimeterStartIndex == 0) {
248 return false;
249 }
250 char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
251 if (potentialEscape == ESCAPE_CHAR) {
252 return true;
253 } else {
254 return false;
255 }
256 }
257
258 final static boolean isDoubleEscaped(String messagePattern,
259 int delimeterStartIndex) {
260 if (delimeterStartIndex >= 2
261 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
262 return true;
263 } else {
264 return false;
265 }
266 }
267
268
269 private static void deeplyAppendParameter(StringBuffer sbuf, Object o,
270 Map seenMap) {
271 if (o == null) {
272 sbuf.append("null");
273 return;
274 }
275 if (!o.getClass().isArray()) {
276 safeObjectAppend(sbuf, o);
277 } else {
278
279
280 if (o instanceof boolean[]) {
281 booleanArrayAppend(sbuf, (boolean[]) o);
282 } else if (o instanceof byte[]) {
283 byteArrayAppend(sbuf, (byte[]) o);
284 } else if (o instanceof char[]) {
285 charArrayAppend(sbuf, (char[]) o);
286 } else if (o instanceof short[]) {
287 shortArrayAppend(sbuf, (short[]) o);
288 } else if (o instanceof int[]) {
289 intArrayAppend(sbuf, (int[]) o);
290 } else if (o instanceof long[]) {
291 longArrayAppend(sbuf, (long[]) o);
292 } else if (o instanceof float[]) {
293 floatArrayAppend(sbuf, (float[]) o);
294 } else if (o instanceof double[]) {
295 doubleArrayAppend(sbuf, (double[]) o);
296 } else {
297 objectArrayAppend(sbuf, (Object[]) o, seenMap);
298 }
299 }
300 }
301
302 private static void safeObjectAppend(StringBuffer sbuf, Object o) {
303 try {
304 String oAsString = o.toString();
305 sbuf.append(oAsString);
306 } catch (Throwable t) {
307 System.err
308 .println("SLF4J: Failed toString() invocation on an object of type ["
309 + o.getClass().getName() + "]");
310 t.printStackTrace();
311 sbuf.append("[FAILED toString()]");
312 }
313
314 }
315
316 private static void objectArrayAppend(StringBuffer sbuf, Object[] a,
317 Map seenMap) {
318 sbuf.append('[');
319 if (!seenMap.containsKey(a)) {
320 seenMap.put(a, null);
321 final int len = a.length;
322 for (int i = 0; i < len; i++) {
323 deeplyAppendParameter(sbuf, a[i], seenMap);
324 if (i != len - 1)
325 sbuf.append(", ");
326 }
327
328 seenMap.remove(a);
329 } else {
330 sbuf.append("...");
331 }
332 sbuf.append(']');
333 }
334
335 private static void booleanArrayAppend(StringBuffer sbuf, boolean[] a) {
336 sbuf.append('[');
337 final int len = a.length;
338 for (int i = 0; i < len; i++) {
339 sbuf.append(a[i]);
340 if (i != len - 1)
341 sbuf.append(", ");
342 }
343 sbuf.append(']');
344 }
345
346 private static void byteArrayAppend(StringBuffer sbuf, byte[] a) {
347 sbuf.append('[');
348 final int len = a.length;
349 for (int i = 0; i < len; i++) {
350 sbuf.append(a[i]);
351 if (i != len - 1)
352 sbuf.append(", ");
353 }
354 sbuf.append(']');
355 }
356
357 private static void charArrayAppend(StringBuffer sbuf, char[] a) {
358 sbuf.append('[');
359 final int len = a.length;
360 for (int i = 0; i < len; i++) {
361 sbuf.append(a[i]);
362 if (i != len - 1)
363 sbuf.append(", ");
364 }
365 sbuf.append(']');
366 }
367
368 private static void shortArrayAppend(StringBuffer sbuf, short[] a) {
369 sbuf.append('[');
370 final int len = a.length;
371 for (int i = 0; i < len; i++) {
372 sbuf.append(a[i]);
373 if (i != len - 1)
374 sbuf.append(", ");
375 }
376 sbuf.append(']');
377 }
378
379 private static void intArrayAppend(StringBuffer sbuf, int[] a) {
380 sbuf.append('[');
381 final int len = a.length;
382 for (int i = 0; i < len; i++) {
383 sbuf.append(a[i]);
384 if (i != len - 1)
385 sbuf.append(", ");
386 }
387 sbuf.append(']');
388 }
389
390 private static void longArrayAppend(StringBuffer sbuf, long[] a) {
391 sbuf.append('[');
392 final int len = a.length;
393 for (int i = 0; i < len; i++) {
394 sbuf.append(a[i]);
395 if (i != len - 1)
396 sbuf.append(", ");
397 }
398 sbuf.append(']');
399 }
400
401 private static void floatArrayAppend(StringBuffer sbuf, float[] a) {
402 sbuf.append('[');
403 final int len = a.length;
404 for (int i = 0; i < len; i++) {
405 sbuf.append(a[i]);
406 if (i != len - 1)
407 sbuf.append(", ");
408 }
409 sbuf.append(']');
410 }
411
412 private static void doubleArrayAppend(StringBuffer sbuf, double[] a) {
413 sbuf.append('[');
414 final int len = a.length;
415 for (int i = 0; i < len; i++) {
416 sbuf.append(a[i]);
417 if (i != len - 1)
418 sbuf.append(", ");
419 }
420 sbuf.append(']');
421 }
422 }