JAL-3026 srcjar files for VARNA and log4j
[jalview.git] / srcjar / org / apache / log4j / pattern / NameAbbreviator.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
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       //  if pattern is just spaces and numbers then
49       //     use MaxElementAbbreviator
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       //  if all blanks and digits
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     //  no matching abbreviation, return defaultAbbreviator
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       // We substract 1 from 'len' when assigning to 'end' to avoid out of
189       // bounds exception in return r.substring(end+1, len). This can happen if
190       // precision is 1 and the category name ends with a dot.
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       //  all non-terminal patterns are executed once
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       //   last pattern in executed repeatedly
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 }