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 * @author Curt Arnold
28 */
29 public abstract class NameAbbreviator {
30 /***
31 * Default (no abbreviation) abbreviator.
32 */
33 private static final NameAbbreviator DEFAULT = new NOPAbbreviator();
34
35 /***
36 * Gets an abbreviator.
37 *
38 * For example, "%logger{2}" will output only 2 elements of 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
58 while (
59 (i < trimmed.length()) && (trimmed.charAt(i) >= '0')
60 && (trimmed.charAt(i) <= '9')) {
61 i++;
62 }
63
64
65
66
67 if (i == trimmed.length()) {
68 return new MaxElementAbbreviator(Integer.parseInt(trimmed));
69 }
70
71 ArrayList fragments = new ArrayList(5);
72 char ellipsis;
73 int charCount;
74 int pos = 0;
75
76 while ((pos < trimmed.length()) && (pos >= 0)) {
77 int ellipsisPos = pos;
78
79 if (trimmed.charAt(pos) == '*') {
80 charCount = Integer.MAX_VALUE;
81 ellipsisPos++;
82 } else {
83 if ((trimmed.charAt(pos) >= '0') && (trimmed.charAt(pos) <= '9')) {
84 charCount = trimmed.charAt(pos) - '0';
85 ellipsisPos++;
86 } else {
87 charCount = 0;
88 }
89 }
90
91 ellipsis = '\0';
92
93 if (ellipsisPos < trimmed.length()) {
94 ellipsis = trimmed.charAt(ellipsisPos);
95
96 if (ellipsis == '.') {
97 ellipsis = '\0';
98 }
99 }
100
101 fragments.add(new PatternAbbreviatorFragment(charCount, ellipsis));
102 pos = trimmed.indexOf(".", pos);
103
104 if (pos == -1) {
105 break;
106 }
107
108 pos++;
109 }
110
111 return new PatternAbbreviator(fragments);
112 }
113
114
115
116
117 return DEFAULT;
118 }
119
120 /***
121 * Gets default abbreviator.
122 *
123 * @return default abbreviator.
124 */
125 public static NameAbbreviator getDefaultAbbreviator() {
126 return DEFAULT;
127 }
128
129 /***
130 * Abbreviates a name in a StringBuffer.
131 *
132 * @param nameStart starting position of name in buf.
133 * @param buf buffer, may not be null.
134 */
135 public abstract void abbreviate(final int nameStart, final StringBuffer buf);
136
137 /***
138 * Abbreviator that simply appends full name to buffer.
139 */
140 private static class NOPAbbreviator extends NameAbbreviator {
141 /***
142 * Constructor.
143 */
144 public NOPAbbreviator() {
145 }
146
147 /***
148 * {@inheritDoc}
149 */
150 public void abbreviate(final int nameStart, final StringBuffer buf) {
151 }
152 }
153
154 /***
155 * Abbreviator that drops starting path elements.
156 */
157 private static class MaxElementAbbreviator extends NameAbbreviator {
158 /***
159 * Maximum number of path elements to output.
160 */
161 private final int count;
162
163 /***
164 * Create new instance.
165 * @param count maximum number of path elements to output.
166 */
167 public MaxElementAbbreviator(final int count) {
168 this.count = count;
169 }
170
171 /***
172 * Abbreviate name.
173 * @param buf buffer to append abbreviation.
174 * @param nameStart start of name to abbreviate.
175 */
176 public void abbreviate(final int nameStart, final StringBuffer buf) {
177
178
179
180 int end = buf.length() - 1;
181
182 String bufString = buf.toString();
183 for (int i = count; i > 0; i--) {
184 end = bufString.lastIndexOf(".", end - 1);
185
186 if ((end == -1) || (end < nameStart)) {
187 return;
188 }
189 }
190
191 buf.delete(nameStart, end + 1);
192 }
193 }
194
195 /***
196 * Fragment of an pattern abbreviator.
197 *
198 */
199 private static class PatternAbbreviatorFragment {
200 /***
201 * Count of initial characters of element to output.
202 */
203 private final int charCount;
204
205 /***
206 * Character used to represent dropped characters.
207 * '\0' indicates no representation of dropped characters.
208 */
209 private final char ellipsis;
210
211 /***
212 * Creates a PatternAbbreviatorFragment.
213 * @param charCount number of initial characters to preserve.
214 * @param ellipsis character to represent elimination of characters,
215 * '\0' if no ellipsis is desired.
216 */
217 public PatternAbbreviatorFragment(
218 final int charCount, final char ellipsis) {
219 this.charCount = charCount;
220 this.ellipsis = ellipsis;
221 }
222
223 /***
224 * Abbreviate element of name.
225 * @param buf buffer to receive element.
226 * @param startPos starting index of name element.
227 * @return starting index of next element.
228 */
229 public int abbreviate(final StringBuffer buf, final int startPos) {
230 int nextDot = buf.toString().indexOf(".", startPos);
231
232 if (nextDot != -1) {
233 if ((nextDot - startPos) > charCount) {
234 buf.delete(startPos + charCount, nextDot);
235 nextDot = startPos + charCount;
236
237 if (ellipsis != '\0') {
238 buf.insert(nextDot, ellipsis);
239 nextDot++;
240 }
241 }
242
243 nextDot++;
244 }
245
246 return nextDot;
247 }
248 }
249
250 /***
251 * Pattern abbreviator.
252 *
253 *
254 */
255 private static class PatternAbbreviator extends NameAbbreviator {
256 /***
257 * Element abbreviation patterns.
258 */
259 private final PatternAbbreviatorFragment[] fragments;
260
261 /***
262 * Create PatternAbbreviator.
263 *
264 * @param fragments element abbreviation patterns.
265 */
266 public PatternAbbreviator(List fragments) {
267 if (fragments.size() == 0) {
268 throw new IllegalArgumentException(
269 "fragments must have at least one element");
270 }
271
272 this.fragments = new PatternAbbreviatorFragment[fragments.size()];
273 fragments.toArray(this.fragments);
274 }
275
276 /***
277 * Abbreviate name.
278 * @param buf buffer that abbreviated name is appended.
279 * @param nameStart start of name.
280 */
281 public void abbreviate(final int nameStart, final StringBuffer buf) {
282
283
284
285 int pos = nameStart;
286
287 for (int i = 0; (i < (fragments.length - 1)) && (pos < buf.length());
288 i++) {
289 pos = fragments[i].abbreviate(buf, pos);
290 }
291
292
293
294
295 PatternAbbreviatorFragment terminalFragment =
296 fragments[fragments.length - 1];
297
298 while ((pos < buf.length()) && (pos >= 0)) {
299 pos = terminalFragment.abbreviate(buf, pos);
300 }
301 }
302 }
303 }