1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.pattern;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23
24 /***
25 * NameAbbreviator generates abbreviated logger and class names.
26 *
27 */
28 public abstract class NameAbbreviator {
29 /***
30 * Default (no abbreviation) abbreviator.
31 */
32 private static final NameAbbreviator DEFAULT = new NOPAbbreviator();
33
34 /***
35 * Gets an abbreviator.
36 *
37 * For example, "%logger{2}" will output only 2 elements of the logger name,
38 * %logger{-2} will drop 2 elements from the logger name,
39 * "%logger{1.}" will output only the first character of the non-final elements in the name,
40 * "%logger(1~.2~} will output the first character of the first element, two characters of
41 * the second and subsequent elements and will use a tilde to indicate abbreviated characters.
42 *
43 * @param pattern abbreviation pattern.
44 * @return abbreviator, will not be null.
45 */
46 public static NameAbbreviator getAbbreviator(final String pattern) {
47 if (pattern.length() > 0) {
48
49
50 String trimmed = pattern.trim();
51
52 if (trimmed.length() == 0) {
53 return DEFAULT;
54 }
55
56 int i = 0;
57 if (trimmed.length() > 0) {
58 if (trimmed.charAt(0) == '-') {
59 i++;
60 }
61 for (;
62 (i < trimmed.length()) &&
63 (trimmed.charAt(i) >= '0') &&
64 (trimmed.charAt(i) <= '9');
65 i++) {
66 }
67 }
68
69
70
71
72
73 if (i == trimmed.length()) {
74 int elements = Integer.parseInt(trimmed);
75 if (elements >= 0) {
76 return new MaxElementAbbreviator(elements);
77 } else {
78 return new DropElementAbbreviator(-elements);
79 }
80 }
81
82 ArrayList fragments = new ArrayList(5);
83 char ellipsis;
84 int charCount;
85 int pos = 0;
86
87 while ((pos < trimmed.length()) && (pos >= 0)) {
88 int ellipsisPos = pos;
89
90 if (trimmed.charAt(pos) == '*') {
91 charCount = Integer.MAX_VALUE;
92 ellipsisPos++;
93 } else {
94 if ((trimmed.charAt(pos) >= '0') && (trimmed.charAt(pos) <= '9')) {
95 charCount = trimmed.charAt(pos) - '0';
96 ellipsisPos++;
97 } else {
98 charCount = 0;
99 }
100 }
101
102 ellipsis = '\0';
103
104 if (ellipsisPos < trimmed.length()) {
105 ellipsis = trimmed.charAt(ellipsisPos);
106
107 if (ellipsis == '.') {
108 ellipsis = '\0';
109 }
110 }
111
112 fragments.add(new PatternAbbreviatorFragment(charCount, ellipsis));
113 pos = trimmed.indexOf(".", pos);
114
115 if (pos == -1) {
116 break;
117 }
118
119 pos++;
120 }
121
122 return new PatternAbbreviator(fragments);
123 }
124
125
126
127
128 return DEFAULT;
129 }
130
131 /***
132 * Gets default abbreviator.
133 *
134 * @return default abbreviator.
135 */
136 public static NameAbbreviator getDefaultAbbreviator() {
137 return DEFAULT;
138 }
139
140 /***
141 * Abbreviates a name in a StringBuffer.
142 *
143 * @param nameStart starting position of name in buf.
144 * @param buf buffer, may not be null.
145 */
146 public abstract void abbreviate(final int nameStart, final StringBuffer buf);
147
148 /***
149 * Abbreviator that simply appends full name to buffer.
150 */
151 private static class NOPAbbreviator extends NameAbbreviator {
152 /***
153 * Constructor.
154 */
155 public NOPAbbreviator() {
156 }
157
158 /***
159 * {@inheritDoc}
160 */
161 public void abbreviate(final int nameStart, final StringBuffer buf) {
162 }
163 }
164
165 /***
166 * Abbreviator that drops starting path elements.
167 */
168 private static class MaxElementAbbreviator extends NameAbbreviator {
169 /***
170 * Maximum number of path elements to output.
171 */
172 private final int count;
173
174 /***
175 * Create new instance.
176 * @param count maximum number of path elements to output.
177 */
178 public MaxElementAbbreviator(final int count) {
179 this.count = count;
180 }
181
182 /***
183 * Abbreviate name.
184 * @param buf buffer to append abbreviation.
185 * @param nameStart start of name to abbreviate.
186 */
187 public void abbreviate(final int nameStart, final StringBuffer buf) {
188
189
190
191 int end = buf.length() - 1;
192
193 String bufString = buf.toString();
194 for (int i = count; i > 0; i--) {
195 end = bufString.lastIndexOf(".", end - 1);
196
197 if ((end == -1) || (end < nameStart)) {
198 return;
199 }
200 }
201
202 buf.delete(nameStart, end + 1);
203 }
204 }
205
206 /***
207 * Abbreviator that drops starting path elements.
208 */
209 private static class DropElementAbbreviator extends NameAbbreviator {
210 /***
211 * Maximum number of path elements to output.
212 */
213 private final int count;
214
215 /***
216 * Create new instance.
217 * @param count maximum number of path elements to output.
218 */
219 public DropElementAbbreviator(final int count) {
220 this.count = count;
221 }
222
223 /***
224 * Abbreviate name.
225 * @param buf buffer to append abbreviation.
226 * @param nameStart start of name to abbreviate.
227 */
228 public void abbreviate(final int nameStart, final StringBuffer buf) {
229 int i = count;
230 for(int pos = buf.indexOf(".", nameStart);
231 pos != -1;
232 pos = buf.indexOf(".", pos + 1)) {
233 if(--i == 0) {
234 buf.delete(nameStart, pos + 1);
235 break;
236 }
237 }
238 }
239 }
240
241
242 /***
243 * Fragment of an pattern abbreviator.
244 *
245 */
246 private static class PatternAbbreviatorFragment {
247 /***
248 * Count of initial characters of element to output.
249 */
250 private final int charCount;
251
252 /***
253 * Character used to represent dropped characters.
254 * '\0' indicates no representation of dropped characters.
255 */
256 private final char ellipsis;
257
258 /***
259 * Creates a PatternAbbreviatorFragment.
260 * @param charCount number of initial characters to preserve.
261 * @param ellipsis character to represent elimination of characters,
262 * '\0' if no ellipsis is desired.
263 */
264 public PatternAbbreviatorFragment(
265 final int charCount, final char ellipsis) {
266 this.charCount = charCount;
267 this.ellipsis = ellipsis;
268 }
269
270 /***
271 * Abbreviate element of name.
272 * @param buf buffer to receive element.
273 * @param startPos starting index of name element.
274 * @return starting index of next element.
275 */
276 public int abbreviate(final StringBuffer buf, final int startPos) {
277 int nextDot = buf.toString().indexOf(".", startPos);
278
279 if (nextDot != -1) {
280 if ((nextDot - startPos) > charCount) {
281 buf.delete(startPos + charCount, nextDot);
282 nextDot = startPos + charCount;
283
284 if (ellipsis != '\0') {
285 buf.insert(nextDot, ellipsis);
286 nextDot++;
287 }
288 }
289
290 nextDot++;
291 }
292
293 return nextDot;
294 }
295 }
296
297 /***
298 * Pattern abbreviator.
299 *
300 *
301 */
302 private static class PatternAbbreviator extends NameAbbreviator {
303 /***
304 * Element abbreviation patterns.
305 */
306 private final PatternAbbreviatorFragment[] fragments;
307
308 /***
309 * Create PatternAbbreviator.
310 *
311 * @param fragments element abbreviation patterns.
312 */
313 public PatternAbbreviator(List fragments) {
314 if (fragments.size() == 0) {
315 throw new IllegalArgumentException(
316 "fragments must have at least one element");
317 }
318
319 this.fragments = new PatternAbbreviatorFragment[fragments.size()];
320 fragments.toArray(this.fragments);
321 }
322
323 /***
324 * Abbreviate name.
325 * @param buf buffer that abbreviated name is appended.
326 * @param nameStart start of name.
327 */
328 public void abbreviate(final int nameStart, final StringBuffer buf) {
329
330
331
332 int pos = nameStart;
333
334 for (int i = 0; (i < (fragments.length - 1)) && (pos < buf.length());
335 i++) {
336 pos = fragments[i].abbreviate(buf, pos);
337 }
338
339
340
341
342 PatternAbbreviatorFragment terminalFragment =
343 fragments[fragments.length - 1];
344
345 while ((pos < buf.length()) && (pos >= 0)) {
346 pos = terminalFragment.abbreviate(buf, pos);
347 }
348 }
349 }
350 }