1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.pattern;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.logging.log4j.util.PerformanceSensitive;
23
24
25
26
27
28 @PerformanceSensitive("allocation")
29 public abstract class NameAbbreviator {
30
31
32
33 private static final NameAbbreviator DEFAULT = new NOPAbbreviator();
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public static NameAbbreviator getAbbreviator(final String pattern) {
49 if (pattern.length() > 0) {
50
51
52 final String trimmed = pattern.trim();
53
54 if (trimmed.isEmpty()) {
55 return DEFAULT;
56 }
57
58 boolean isNegativeNumber;
59 final String number;
60
61
62 if (trimmed.length() > 1 && trimmed.charAt(0) == '-') {
63 isNegativeNumber = true;
64 number = trimmed.substring(1);
65 } else {
66 isNegativeNumber = false;
67 number = trimmed;
68 }
69
70 int i = 0;
71
72 while (i < number.length() && number.charAt(i) >= '0'
73 && number.charAt(i) <= '9') {
74 i++;
75 }
76
77
78
79
80 if (i == number.length()) {
81 return new MaxElementAbbreviator(Integer.parseInt(number),
82 isNegativeNumber? MaxElementAbbreviator.Strategy.DROP : MaxElementAbbreviator.Strategy.RETAIN);
83 }
84
85 final ArrayList<PatternAbbreviatorFragment> fragments = new ArrayList<>(5);
86 char ellipsis;
87 int charCount;
88 int pos = 0;
89
90 while (pos < trimmed.length() && pos >= 0) {
91 int ellipsisPos = pos;
92
93 if (trimmed.charAt(pos) == '*') {
94 charCount = Integer.MAX_VALUE;
95 ellipsisPos++;
96 } else {
97 if (trimmed.charAt(pos) >= '0' && trimmed.charAt(pos) <= '9') {
98 charCount = trimmed.charAt(pos) - '0';
99 ellipsisPos++;
100 } else {
101 charCount = 0;
102 }
103 }
104
105 ellipsis = '\0';
106
107 if (ellipsisPos < trimmed.length()) {
108 ellipsis = trimmed.charAt(ellipsisPos);
109
110 if (ellipsis == '.') {
111 ellipsis = '\0';
112 }
113 }
114
115 fragments.add(new PatternAbbreviatorFragment(charCount, ellipsis));
116 pos = trimmed.indexOf('.', pos);
117
118 if (pos == -1) {
119 break;
120 }
121
122 pos++;
123 }
124
125 return new PatternAbbreviator(fragments);
126 }
127
128
129
130
131 return DEFAULT;
132 }
133
134
135
136
137
138
139 public static NameAbbreviator getDefaultAbbreviator() {
140 return DEFAULT;
141 }
142
143
144
145
146
147
148
149 public abstract void abbreviate(final String original, final StringBuilder destination);
150
151
152
153
154 private static class NOPAbbreviator extends NameAbbreviator {
155
156
157
158 public NOPAbbreviator() {
159 }
160
161
162
163
164 @Override
165 public void abbreviate(final String original, final StringBuilder destination) {
166 destination.append(original);
167 }
168 }
169
170
171
172
173 private static class MaxElementAbbreviator extends NameAbbreviator {
174
175
176
177
178
179
180 private enum Strategy {
181 DROP(0) {
182 @Override
183 void abbreviate(final int count, final String original, final StringBuilder destination) {
184
185 int start = 0;
186 int nextStart;
187 for (int i = 0; i < count; i++) {
188 nextStart = original.indexOf('.', start);
189 if (nextStart == -1) {
190 destination.append(original);
191 return;
192 }
193 start = nextStart + 1;
194 }
195 destination.append(original, start, original.length());
196 }
197 },
198 RETAIN(1) {
199 @Override
200 void abbreviate(final int count, final String original, final StringBuilder destination) {
201
202
203
204 int end = original.length() - 1;
205
206 for (int i = count; i > 0; i--) {
207 end = original.lastIndexOf('.', end - 1);
208 if (end == -1) {
209 destination.append(original);
210 return;
211 }
212 }
213 destination.append(original, end + 1, original.length());
214 }
215 };
216
217 final int minCount;
218
219 Strategy(final int minCount) {
220 this.minCount = minCount;
221 }
222
223 abstract void abbreviate(final int count, final String original, final StringBuilder destination);
224 }
225
226
227
228
229 private final int count;
230
231
232
233
234 private final Strategy strategy;
235
236
237
238
239
240
241
242 public MaxElementAbbreviator(final int count, final Strategy strategy) {
243 this.count = Math.max(count, strategy.minCount);
244 this.strategy = strategy;
245 }
246
247
248
249
250
251
252
253 @Override
254 public void abbreviate(final String original, final StringBuilder destination) {
255 strategy.abbreviate(count, original, destination);
256 }
257 }
258
259
260
261
262 private static class PatternAbbreviatorFragment {
263
264
265
266 private final int charCount;
267
268
269
270
271
272 private final char ellipsis;
273
274
275
276
277
278
279
280
281 public PatternAbbreviatorFragment(
282 final int charCount, final char ellipsis) {
283 this.charCount = charCount;
284 this.ellipsis = ellipsis;
285 }
286
287
288
289
290
291
292
293
294 public int abbreviate(final StringBuilder buf, final int startPos) {
295 final int start = (startPos < 0) ? 0 : startPos;
296 final int max = buf.length();
297 int nextDot = -1;
298 for (int i = start; i < max; i++) {
299 if (buf.charAt(i) == '.') {
300 nextDot = i;
301 break;
302 }
303 }
304 if (nextDot != -1) {
305 if (nextDot - startPos > charCount) {
306 buf.delete(startPos + charCount, nextDot);
307 nextDot = startPos + charCount;
308
309 if (ellipsis != '\0') {
310 buf.insert(nextDot, ellipsis);
311 nextDot++;
312 }
313 }
314 nextDot++;
315 }
316 return nextDot;
317 }
318 }
319
320
321
322
323 private static class PatternAbbreviator extends NameAbbreviator {
324
325
326
327 private final PatternAbbreviatorFragment[] fragments;
328
329
330
331
332
333
334 public PatternAbbreviator(final List<PatternAbbreviatorFragment> fragments) {
335 if (fragments.isEmpty()) {
336 throw new IllegalArgumentException(
337 "fragments must have at least one element");
338 }
339
340 this.fragments = new PatternAbbreviatorFragment[fragments.size()];
341 fragments.toArray(this.fragments);
342 }
343
344
345
346
347
348
349
350 @Override
351 public void abbreviate(final String original, final StringBuilder destination) {
352
353
354
355 int pos = destination.length();
356 final int max = pos + original.length();
357
358 destination.append(original);
359
360 int fragmentIndex = 0;
361 while (pos < max && pos >= 0) {
362 pos = fragments[fragmentIndex].abbreviate(destination, pos);
363
364 if (fragmentIndex < fragments.length - 1) {
365 fragmentIndex++;
366 }
367 }
368 }
369 }
370 }