1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.message;
18
19 import java.util.Arrays;
20
21 import org.apache.logging.log4j.util.Constants;
22 import org.apache.logging.log4j.util.PerformanceSensitive;
23 import org.apache.logging.log4j.util.StringBuilders;
24
25
26
27
28
29
30
31
32 @PerformanceSensitive("allocation")
33 public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitable, Clearable {
34
35 private static final int MIN_BUILDER_SIZE = 512;
36 private static final int MAX_PARMS = 10;
37 private static final long serialVersionUID = 7800075879295123856L;
38 private transient ThreadLocal<StringBuilder> buffer;
39
40 private String messagePattern;
41 private int argCount;
42 private int usedCount;
43 private final int[] indices = new int[256];
44 private transient Object[] varargs;
45 private transient Object[] params = new Object[MAX_PARMS];
46 private transient Throwable throwable;
47 transient boolean reserved = false;
48
49
50
51
52 public ReusableParameterizedMessage() {
53 }
54
55 private Object[] getTrimmedParams() {
56 return varargs == null ? Arrays.copyOf(params, argCount) : varargs;
57 }
58
59 private Object[] getParams() {
60 return varargs == null ? params : varargs;
61 }
62
63
64 @Override
65 public Object[] swapParameters(final Object[] emptyReplacement) {
66 Object[] result;
67 if (varargs == null) {
68 result = params;
69 if (emptyReplacement.length >= MAX_PARMS) {
70 params = emptyReplacement;
71 } else if (argCount <= emptyReplacement.length) {
72
73
74 System.arraycopy(params, 0, emptyReplacement, 0, argCount);
75
76 for (int i = 0; i < argCount; i++) {
77 params[i] = null;
78 }
79 result = emptyReplacement;
80 } else {
81
82 params = new Object[MAX_PARMS];
83 }
84 } else {
85
86
87
88
89
90
91
92 if (argCount <= emptyReplacement.length) {
93 result = emptyReplacement;
94 } else {
95 result = new Object[argCount];
96 }
97
98 System.arraycopy(varargs, 0, result, 0, argCount);
99 }
100 return result;
101 }
102
103
104 @Override
105 public short getParameterCount() {
106 return (short) argCount;
107 }
108
109 @Override
110 public <S> void forEachParameter(final ParameterConsumer<S> action, final S state) {
111 final Object[] parameters = getParams();
112 for (short i = 0; i < argCount; i++) {
113 action.accept(parameters[i], i, state);
114 }
115 }
116
117 @Override
118 public Message memento() {
119 return new ParameterizedMessage(messagePattern, getTrimmedParams());
120 }
121
122 private void init(final String messagePattern, final int argCount, final Object[] paramArray) {
123 this.varargs = null;
124 this.messagePattern = messagePattern;
125 this.argCount = argCount;
126 final int placeholderCount = count(messagePattern, indices);
127 initThrowable(paramArray, argCount, placeholderCount);
128 this.usedCount = Math.min(placeholderCount, argCount);
129 }
130
131 private static int count(final String messagePattern, final int[] indices) {
132 try {
133
134 return ParameterFormatter.countArgumentPlaceholders2(messagePattern, indices);
135 } catch (final Exception ex) {
136 return ParameterFormatter.countArgumentPlaceholders(messagePattern);
137 }
138 }
139
140 private void initThrowable(final Object[] params, final int argCount, final int usedParams) {
141 if (usedParams < argCount && params[argCount - 1] instanceof Throwable) {
142 this.throwable = (Throwable) params[argCount - 1];
143 } else {
144 this.throwable = null;
145 }
146 }
147
148 ReusableParameterizedMessage set(final String messagePattern, final Object... arguments) {
149 init(messagePattern, arguments == null ? 0 : arguments.length, arguments);
150 varargs = arguments;
151 return this;
152 }
153
154 ReusableParameterizedMessage set(final String messagePattern, final Object p0) {
155 params[0] = p0;
156 init(messagePattern, 1, params);
157 return this;
158 }
159
160 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1) {
161 params[0] = p0;
162 params[1] = p1;
163 init(messagePattern, 2, params);
164 return this;
165 }
166
167 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2) {
168 params[0] = p0;
169 params[1] = p1;
170 params[2] = p2;
171 init(messagePattern, 3, params);
172 return this;
173 }
174
175 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3) {
176 params[0] = p0;
177 params[1] = p1;
178 params[2] = p2;
179 params[3] = p3;
180 init(messagePattern, 4, params);
181 return this;
182 }
183
184 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4) {
185 params[0] = p0;
186 params[1] = p1;
187 params[2] = p2;
188 params[3] = p3;
189 params[4] = p4;
190 init(messagePattern, 5, params);
191 return this;
192 }
193
194 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5) {
195 params[0] = p0;
196 params[1] = p1;
197 params[2] = p2;
198 params[3] = p3;
199 params[4] = p4;
200 params[5] = p5;
201 init(messagePattern, 6, params);
202 return this;
203 }
204
205 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
206 final Object p6) {
207 params[0] = p0;
208 params[1] = p1;
209 params[2] = p2;
210 params[3] = p3;
211 params[4] = p4;
212 params[5] = p5;
213 params[6] = p6;
214 init(messagePattern, 7, params);
215 return this;
216 }
217
218 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
219 final Object p6, final Object p7) {
220 params[0] = p0;
221 params[1] = p1;
222 params[2] = p2;
223 params[3] = p3;
224 params[4] = p4;
225 params[5] = p5;
226 params[6] = p6;
227 params[7] = p7;
228 init(messagePattern, 8, params);
229 return this;
230 }
231
232 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
233 final Object p6, final Object p7, final Object p8) {
234 params[0] = p0;
235 params[1] = p1;
236 params[2] = p2;
237 params[3] = p3;
238 params[4] = p4;
239 params[5] = p5;
240 params[6] = p6;
241 params[7] = p7;
242 params[8] = p8;
243 init(messagePattern, 9, params);
244 return this;
245 }
246
247 ReusableParameterizedMessage set(final String messagePattern, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
248 final Object p6, final Object p7, final Object p8, final Object p9) {
249 params[0] = p0;
250 params[1] = p1;
251 params[2] = p2;
252 params[3] = p3;
253 params[4] = p4;
254 params[5] = p5;
255 params[6] = p6;
256 params[7] = p7;
257 params[8] = p8;
258 params[9] = p9;
259 init(messagePattern, 10, params);
260 return this;
261 }
262
263
264
265
266
267 @Override
268 public String getFormat() {
269 return messagePattern;
270 }
271
272
273
274
275
276 @Override
277 public Object[] getParameters() {
278 return getTrimmedParams();
279 }
280
281
282
283
284
285
286
287
288
289
290 @Override
291 public Throwable getThrowable() {
292 return throwable;
293 }
294
295
296
297
298
299 @Override
300 public String getFormattedMessage() {
301 final StringBuilder sb = getBuffer();
302 formatTo(sb);
303 final String result = sb.toString();
304 StringBuilders.trimToMaxSize(sb, Constants.MAX_REUSABLE_MESSAGE_SIZE);
305 return result;
306 }
307
308 private StringBuilder getBuffer() {
309 if (buffer == null) {
310 buffer = new ThreadLocal<>();
311 }
312 StringBuilder result = buffer.get();
313 if (result == null) {
314 final int currentPatternLength = messagePattern == null ? 0 : messagePattern.length();
315 result = new StringBuilder(Math.max(MIN_BUILDER_SIZE, currentPatternLength * 2));
316 buffer.set(result);
317 }
318 result.setLength(0);
319 return result;
320 }
321
322 @Override
323 public void formatTo(final StringBuilder builder) {
324 if (indices[0] < 0) {
325 ParameterFormatter.formatMessage(builder, messagePattern, getParams(), argCount);
326 } else {
327 ParameterFormatter.formatMessage2(builder, messagePattern, getParams(), usedCount, indices);
328 }
329 }
330
331
332
333
334
335
336 ReusableParameterizedMessage reserve() {
337 reserved = true;
338 return this;
339 }
340
341 @Override
342 public String toString() {
343 return "ReusableParameterizedMessage[messagePattern=" + getFormat() + ", stringArgs=" +
344 Arrays.toString(getParameters()) + ", throwable=" + getThrowable() + ']';
345 }
346
347 @Override
348 public void clear() {
349
350
351 reserved = false;
352 varargs = null;
353 messagePattern = null;
354 throwable = null;
355 }
356 }