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