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