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