KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > util > log > ExtensiblePatternFormatter


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.util.log;
17
18 import java.io.StringWriter JavaDoc;
19 import java.util.Stack JavaDoc;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.commons.lang.SystemUtils;
23 import org.apache.log.LogEvent;
24 import org.apache.log.Priority;
25 import org.apache.log.format.Formatter;
26 import org.apache.log.util.DefaultErrorHandler;
27
28 /**
29  * A refactoring of <code>org.apache.log.format.PatternFormatter</code> that
30  * can be extended.
31  * This formater formats the LogEntries according to a input pattern string.
32  *
33  * The format of each pattern element can be %[+|-]#.#{field:subformat}
34  *
35  * The +|- indicates left or right justify.
36  * The #.# indicates the minimum and maximum size of output.
37  * 'field' indicates which field is to be output and must be one of
38  * properties of LogEvent
39  * 'subformat' indicates a particular subformat and is currently unused.
40  *
41  * @author <a HREF="mailto:donaldp@apache.org">Peter Donald</a>
42  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
43  * @version CVS $Id: ExtensiblePatternFormatter.java 30932 2004-07-29 17:35:38Z vgritsenko $
44  */

45 public class ExtensiblePatternFormatter
46     implements Formatter
47 {
48     protected final static int TYPE_TEXT = 1;
49     protected final static int TYPE_CATEGORY = 2;
50     protected final static int TYPE_MESSAGE = 4;
51     protected final static int TYPE_TIME = 5;
52     protected final static int TYPE_RELATIVE_TIME = 6;
53     protected final static int TYPE_THROWABLE = 7;
54     protected final static int TYPE_PRIORITY = 8;
55
56     /**
57      * The maximum value used for TYPEs. Subclasses can define their own TYPEs
58      * starting at <code>MAX_TYPE + 1</code>.
59      */

60     protected final static int MAX_TYPE = 8;
61
62     protected final static String JavaDoc TYPE_CATEGORY_STR = "category";
63     protected final static String JavaDoc TYPE_MESSAGE_STR = "message";
64     protected final static String JavaDoc TYPE_TIME_STR = "time";
65     protected final static String JavaDoc TYPE_RELATIVE_TIME_STR = "rtime";
66     protected final static String JavaDoc TYPE_THROWABLE_STR = "throwable";
67     protected final static String JavaDoc TYPE_PRIORITY_STR = "priority";
68
69     protected static class PatternRun {
70         public String JavaDoc m_data;
71         public boolean m_rightJustify;
72         public int m_minSize;
73         public int m_maxSize;
74         public int m_type;
75         public String JavaDoc m_format;
76     }
77
78     protected PatternRun m_formatSpecification[];
79
80     /**
81      * Extract and build a pattern from input string.
82      *
83      * @param stack the stack on which to place patterns
84      * @param pattern the input string
85      * @param index the start of pattern run
86      * @return the number of characters in pattern run
87      */

88     protected int addPatternRun(final Stack JavaDoc stack, final char pattern[], int index) {
89         final PatternRun run = new PatternRun();
90         final int start = index++;
91
92         // first check for a +|- sign
93
if ('+' == pattern[index]) {
94             index++;
95         } else if ('-' == pattern[index]) {
96             run.m_rightJustify = true;
97             index++;
98         }
99
100         if (Character.isDigit(pattern[index])) {
101             int total = 0;
102             while (Character.isDigit(pattern[index])) {
103                 total = total * 10 + (pattern[index] - '0');
104                 index++;
105             }
106             run.m_minSize = total;
107         }
108
109         //check for . sign indicating a maximum is to follow
110
if (index < pattern.length && '.' == pattern[index]) {
111             index++;
112             if (Character.isDigit(pattern[index])) {
113                 int total = 0;
114                 while (Character.isDigit(pattern[index])) {
115                     total = total * 10 + (pattern[ index ] - '0');
116                     index++;
117                 }
118                 run.m_maxSize = total;
119             }
120         }
121
122         if (index >= pattern.length || '{' != pattern[index]) {
123             throw new IllegalArgumentException JavaDoc(
124                     "Badly formed pattern at character " + index );
125         }
126
127         int typeStart = index;
128
129         while (index < pattern.length &&
130                pattern[index]!= ':' && pattern[index] != '}' ) {
131             index++;
132         }
133
134         int typeEnd = index - 1;
135
136         final String JavaDoc type = new String JavaDoc(pattern, typeStart + 1, typeEnd - typeStart);
137
138         run.m_type = getTypeIdFor( type );
139
140         if (index < pattern.length && pattern[index] == ':' ) {
141             index++;
142             while (index < pattern.length && pattern[index] != '}' ) {
143                 index++;
144             }
145             final int length = index - typeEnd - 2;
146
147             if (0 != length) {
148                 run.m_format = new String JavaDoc(pattern, typeEnd + 2, length);
149             }
150         }
151
152         if (index >= pattern.length || '}' != pattern[index]) {
153             throw new IllegalArgumentException JavaDoc(
154                     "Unterminated type in pattern at character " + index );
155         }
156         index++;
157         stack.push( run );
158         return index - start;
159     }
160
161     /**
162      * Extract and build a text run from input string.
163      * It does special handling of '\n' and '\t' replaceing
164      * them with newline and tab.
165      *
166      * @param stack the stack on which to place runs
167      * @param pattern the input string
168      * @param index the start of the text run
169      * @return the number of characters in run
170      */

171     protected int addTextRun( final Stack JavaDoc stack, final char pattern[], int index ) {
172         final PatternRun run = new PatternRun();
173         final int start = index;
174         boolean escapeMode = false;
175
176         if ('%' == pattern[index]) {
177             index++;
178         }
179         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
180         while (index < pattern.length && pattern[index] != '%') {
181             if (escapeMode) {
182                 if ('n' == pattern[ index ]) {
183                     sb.append( SystemUtils.LINE_SEPARATOR );
184                 } else if ('t' == pattern[ index ]) {
185                     sb.append( '\t' );
186                 } else {
187                     sb.append( pattern[ index ] );
188                 }
189                 escapeMode = false;
190             } else if ('\\' == pattern[ index ]) {
191                 escapeMode = true;
192             } else {
193                 sb.append( pattern[ index ] );
194             }
195             index++;
196         }
197         run.m_data = sb.toString();
198         run.m_type = TYPE_TEXT;
199         stack.push(run);
200         return index - start;
201     }
202
203     /**
204      * Utility to append a string to buffer given certain constraints.
205      *
206      * @param sb the StringBuffer
207      * @param minSize the minimum size of output (0 to ignore)
208      * @param maxSize the maximum size of output (0 to ignore)
209      * @param rightJustify true if the string is to be right justified in it's box.
210      * @param output the input string
211      */

212     protected void append(final StringBuffer JavaDoc sb, final int minSize, final int maxSize,
213             final boolean rightJustify, final String JavaDoc output) {
214         if (output.length() < minSize) {
215             if (rightJustify) {
216                 sb.append(StringUtils.leftPad(output, minSize));
217             } else {
218                 sb.append(StringUtils.rightPad(output, minSize));
219             }
220         } else if (maxSize > 0) {
221             if (rightJustify) {
222                 sb.append(StringUtils.right(output, maxSize));
223             } else {
224                 sb.append(StringUtils.left(output, maxSize));
225             }
226         } else {
227             sb.append(output);
228         }
229     }
230
231     /**
232      * Format the event according to the pattern.
233      *
234      * @param event the event
235      * @return the formatted output
236      */

237     public String JavaDoc format(final LogEvent event) {
238         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
239
240         for( int i = 0; i < m_formatSpecification.length; i++ ) {
241             final PatternRun run = m_formatSpecification[i];
242             //treat text differently as it doesn't need min/max padding
243
if (run.m_type == TYPE_TEXT) {
244                 sb.append(run.m_data);
245             } else {
246                 final String JavaDoc data = formatPatternRun(event, run);
247                 if (null != data) {
248                     append(sb, run.m_minSize, run.m_maxSize, run.m_rightJustify, data);
249                 }
250             }
251         }
252         return sb.toString();
253     }
254
255     /**
256      * Formats a single pattern run (can be extended in subclasses).
257      *
258      * @param run the pattern run to format.
259      * @return the formatted result.
260      */

261     protected String JavaDoc formatPatternRun( final LogEvent event, final PatternRun run )
262     {
263         String JavaDoc str = null;
264
265         switch (run.m_type)
266         {
267             case TYPE_RELATIVE_TIME:
268                 str = getTime( event.getRelativeTime(), run.m_format );
269                 break;
270             case TYPE_TIME:
271                 str = getTime( event.getTime(), run.m_format );
272                 break;
273             case TYPE_THROWABLE:
274                 str = getStackTrace( event.getThrowable(), run.m_format );
275                 break;
276             case TYPE_MESSAGE:
277                 str = getMessage( event.getMessage(), run.m_format );
278                 break;
279             case TYPE_CATEGORY:
280                 str = getCategory( event.getCategory(), run.m_format );
281                 break;
282             case TYPE_PRIORITY:
283                 str = getPriority( event.getPriority(), run.m_format );
284                 break;
285             default:
286                 new DefaultErrorHandler().error("Unknown Pattern specification." + run.m_type, null, null);
287         }
288         return str;
289     }
290
291     /**
292      * Utility method to format category.
293      *
294      * @param category the category string
295      * @param format ancilliary format parameter - allowed to be null
296      * @return the formatted string
297      */

298     protected String JavaDoc getCategory(final String JavaDoc category, final String JavaDoc format) {
299         return category;
300     }
301
302     /**
303      * Get formatted priority string.
304      */

305     protected String JavaDoc getPriority(final Priority priority, final String JavaDoc format) {
306         return priority.getName();
307     }
308
309     /**
310      * Correct a context string by replacing '.''s with a '_'.
311      *
312      * @param context the un-fixed context
313      * @return the fixed context
314      */

315     protected final String JavaDoc fix(final String JavaDoc context) {
316         return context.replace( '.', '_' );
317     }
318
319     /**
320      * Utility method to format message.
321      *
322      * @param message the message string
323      * @param format ancilliary format parameter - allowed to be null
324      * @return the formatted string
325      */

326     protected String JavaDoc getMessage(final String JavaDoc message, final String JavaDoc format) {
327         return message;
328     }
329
330     /**
331      * Utility method to format stack trace.
332      *
333      * @param throwable the throwable instance
334      * @param format ancilliary format parameter - allowed to be null
335      * @return the formatted string
336      */

337     protected String JavaDoc getStackTrace(final Throwable JavaDoc throwable, final String JavaDoc format) {
338         if (null != throwable) {
339             final StringWriter JavaDoc sw = new StringWriter JavaDoc();
340             throwable.printStackTrace(new java.io.PrintWriter JavaDoc(sw));
341             return sw.toString();
342         }
343         return "";
344     }
345
346     /**
347      * Utility method to format time.
348      *
349      * @param time the time
350      * @param format ancilliary format parameter - allowed to be null
351      * @return the formatted string
352      */

353     protected String JavaDoc getTime(final long time, final String JavaDoc format) {
354         return Long.toString(time);
355     }
356
357     /**
358      * Retrieve the type-id for a particular string.
359      *
360      * @param type the string
361      * @return the type-id
362      */

363     protected int getTypeIdFor(final String JavaDoc type) {
364         if (type.equalsIgnoreCase(TYPE_CATEGORY_STR)) {
365             return TYPE_CATEGORY;
366         } else if (type.equalsIgnoreCase(TYPE_MESSAGE_STR)) {
367             return TYPE_MESSAGE;
368         } else if (type.equalsIgnoreCase(TYPE_PRIORITY_STR)) {
369             return TYPE_PRIORITY;
370         } else if (type.equalsIgnoreCase(TYPE_TIME_STR)) {
371             return TYPE_TIME;
372         } else if (type.equalsIgnoreCase(TYPE_RELATIVE_TIME_STR)) {
373             return TYPE_RELATIVE_TIME;
374         } else if (type.equalsIgnoreCase(TYPE_THROWABLE_STR)) {
375             return TYPE_THROWABLE;
376         } else {
377             throw new IllegalArgumentException JavaDoc( "Unknown Type in pattern - " + type );
378         }
379     }
380
381     /**
382      * Parse the input pattern and build internal data structures.
383      *
384      * @param patternString the pattern
385      */

386     protected void parse(final String JavaDoc patternString) {
387         final Stack JavaDoc stack = new Stack JavaDoc();
388         final int size = patternString.length();
389         final char pattern[] = new char[size];
390         int index = 0;
391
392         patternString.getChars(0, size, pattern, 0);
393         while (index < size) {
394             if (pattern[index] == '%' &&
395                 !(index != size - 1 && pattern[index + 1] == '%' )) {
396                 index += addPatternRun(stack, pattern, index);
397             } else {
398                 index += addTextRun(stack, pattern, index);
399             }
400         }
401         final int elementCount = stack.size();
402         m_formatSpecification = new PatternRun[elementCount];
403
404         for (int i = 0; i < elementCount; i++) {
405             m_formatSpecification[i] = (PatternRun) stack.elementAt(i);
406         }
407     }
408
409     /**
410      * Set the string description that the format is extracted from.
411      *
412      * @param format the string format
413      */

414     public void setFormat(final String JavaDoc format) {
415         parse(format);
416     }
417 }
418
Popular Tags