KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log4j > helpers > PatternParser


1 /*
2  * Copyright 1999-2005 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.log4j.helpers;
17
18 import org.apache.log4j.helpers.LogLog;
19 import org.apache.log4j.helpers.OptionConverter;
20 import org.apache.log4j.helpers.AbsoluteTimeDateFormat;
21 import org.apache.log4j.Layout;
22 import org.apache.log4j.spi.LoggingEvent;
23 import org.apache.log4j.spi.LocationInfo;
24 import java.text.DateFormat JavaDoc;
25 import java.text.SimpleDateFormat JavaDoc;
26 import java.util.Date JavaDoc;
27
28 // Contributors: Nelson Minar <(nelson@monkey.org>
29
// Igor E. Poteryaev <jah@mail.ru>
30
// Reinhard Deschler <reinhard.deschler@web.de>
31

32 /**
33    Most of the work of the {@link org.apache.log4j.PatternLayout} class
34    is delegated to the PatternParser class.
35
36    <p>It is this class that parses conversion patterns and creates
37    a chained list of {@link OptionConverter OptionConverters}.
38
39    @author <a HREF=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
40    @author Ceki G&uuml;lc&uuml;
41    @author Anders Kristensen
42
43    @since 0.8.2
44 */

45 public class PatternParser {
46
47   private static final char ESCAPE_CHAR = '%';
48
49   private static final int LITERAL_STATE = 0;
50   private static final int CONVERTER_STATE = 1;
51   private static final int MINUS_STATE = 2;
52   private static final int DOT_STATE = 3;
53   private static final int MIN_STATE = 4;
54   private static final int MAX_STATE = 5;
55
56   static final int FULL_LOCATION_CONVERTER = 1000;
57   static final int METHOD_LOCATION_CONVERTER = 1001;
58   static final int CLASS_LOCATION_CONVERTER = 1002;
59   static final int LINE_LOCATION_CONVERTER = 1003;
60   static final int FILE_LOCATION_CONVERTER = 1004;
61
62   static final int RELATIVE_TIME_CONVERTER = 2000;
63   static final int THREAD_CONVERTER = 2001;
64   static final int LEVEL_CONVERTER = 2002;
65   static final int NDC_CONVERTER = 2003;
66   static final int MESSAGE_CONVERTER = 2004;
67
68   int state;
69   protected StringBuffer JavaDoc currentLiteral = new StringBuffer JavaDoc(32);
70   protected int patternLength;
71   protected int i;
72   PatternConverter head;
73   PatternConverter tail;
74   protected FormattingInfo formattingInfo = new FormattingInfo();
75   protected String JavaDoc pattern;
76
77   public
78   PatternParser(String JavaDoc pattern) {
79     this.pattern = pattern;
80     patternLength = pattern.length();
81     state = LITERAL_STATE;
82   }
83
84   private
85   void addToList(PatternConverter pc) {
86     if(head == null) {
87       head = tail = pc;
88     } else {
89       tail.next = pc;
90       tail = pc;
91     }
92   }
93
94   protected
95   String JavaDoc extractOption() {
96     if((i < patternLength) && (pattern.charAt(i) == '{')) {
97       int end = pattern.indexOf('}', i);
98       if (end > i) {
99     String JavaDoc r = pattern.substring(i + 1, end);
100     i = end+1;
101     return r;
102       }
103     }
104     return null;
105   }
106
107
108   /**
109      The option is expected to be in decimal and positive. In case of
110      error, zero is returned. */

111   protected
112   int extractPrecisionOption() {
113     String JavaDoc opt = extractOption();
114     int r = 0;
115     if(opt != null) {
116       try {
117     r = Integer.parseInt(opt);
118     if(r <= 0) {
119         LogLog.error(
120             "Precision option (" + opt + ") isn't a positive integer.");
121         r = 0;
122     }
123       }
124       catch (NumberFormatException JavaDoc e) {
125     LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
126       }
127     }
128     return r;
129   }
130
131   public
132   PatternConverter parse() {
133     char c;
134     i = 0;
135     while(i < patternLength) {
136       c = pattern.charAt(i++);
137       switch(state) {
138       case LITERAL_STATE:
139         // In literal state, the last char is always a literal.
140
if(i == patternLength) {
141           currentLiteral.append(c);
142           continue;
143         }
144         if(c == ESCAPE_CHAR) {
145           // peek at the next char.
146
switch(pattern.charAt(i)) {
147           case ESCAPE_CHAR:
148             currentLiteral.append(c);
149             i++; // move pointer
150
break;
151           case 'n':
152             currentLiteral.append(Layout.LINE_SEP);
153             i++; // move pointer
154
break;
155           default:
156             if(currentLiteral.length() != 0) {
157               addToList(new LiteralPatternConverter(
158                                                   currentLiteral.toString()));
159               //LogLog.debug("Parsed LITERAL converter: \""
160
// +currentLiteral+"\".");
161
}
162             currentLiteral.setLength(0);
163             currentLiteral.append(c); // append %
164
state = CONVERTER_STATE;
165             formattingInfo.reset();
166           }
167         }
168         else {
169           currentLiteral.append(c);
170         }
171         break;
172       case CONVERTER_STATE:
173     currentLiteral.append(c);
174     switch(c) {
175     case '-':
176       formattingInfo.leftAlign = true;
177       break;
178     case '.':
179       state = DOT_STATE;
180       break;
181     default:
182       if(c >= '0' && c <= '9') {
183         formattingInfo.min = c - '0';
184         state = MIN_STATE;
185       }
186       else
187         finalizeConverter(c);
188     } // switch
189
break;
190       case MIN_STATE:
191     currentLiteral.append(c);
192     if(c >= '0' && c <= '9')
193       formattingInfo.min = formattingInfo.min*10 + (c - '0');
194     else if(c == '.')
195       state = DOT_STATE;
196     else {
197       finalizeConverter(c);
198     }
199     break;
200       case DOT_STATE:
201     currentLiteral.append(c);
202     if(c >= '0' && c <= '9') {
203       formattingInfo.max = c - '0';
204        state = MAX_STATE;
205     }
206     else {
207       LogLog.error("Error occured in position "+i
208              +".\n Was expecting digit, instead got char \""+c+"\".");
209       state = LITERAL_STATE;
210     }
211     break;
212       case MAX_STATE:
213     currentLiteral.append(c);
214     if(c >= '0' && c <= '9')
215       formattingInfo.max = formattingInfo.max*10 + (c - '0');
216     else {
217       finalizeConverter(c);
218       state = LITERAL_STATE;
219     }
220     break;
221       } // switch
222
} // while
223
if(currentLiteral.length() != 0) {
224       addToList(new LiteralPatternConverter(currentLiteral.toString()));
225       //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
226
}
227     return head;
228   }
229
230   protected
231   void finalizeConverter(char c) {
232     PatternConverter pc = null;
233     switch(c) {
234     case 'c':
235       pc = new CategoryPatternConverter(formattingInfo,
236                     extractPrecisionOption());
237       //LogLog.debug("CATEGORY converter.");
238
//formattingInfo.dump();
239
currentLiteral.setLength(0);
240       break;
241     case 'C':
242       pc = new ClassNamePatternConverter(formattingInfo,
243                      extractPrecisionOption());
244       //LogLog.debug("CLASS_NAME converter.");
245
//formattingInfo.dump();
246
currentLiteral.setLength(0);
247       break;
248     case 'd':
249       String JavaDoc dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
250       DateFormat df;
251       String JavaDoc dOpt = extractOption();
252       if(dOpt != null)
253     dateFormatStr = dOpt;
254
255       if(dateFormatStr.equalsIgnoreCase(
256                                     AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
257     df = new ISO8601DateFormat();
258       else if(dateFormatStr.equalsIgnoreCase(
259                                    AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
260     df = new AbsoluteTimeDateFormat();
261       else if(dateFormatStr.equalsIgnoreCase(
262                               AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
263     df = new DateTimeDateFormat();
264       else {
265     try {
266       df = new SimpleDateFormat JavaDoc(dateFormatStr);
267     }
268     catch (IllegalArgumentException JavaDoc e) {
269       LogLog.error("Could not instantiate SimpleDateFormat with " +
270                dateFormatStr, e);
271       df = (DateFormat) OptionConverter.instantiateByClassName(
272                        "org.apache.log4j.helpers.ISO8601DateFormat",
273                    DateFormat.class, null);
274     }
275       }
276       pc = new DatePatternConverter(formattingInfo, df);
277       //LogLog.debug("DATE converter {"+dateFormatStr+"}.");
278
//formattingInfo.dump();
279
currentLiteral.setLength(0);
280       break;
281     case 'F':
282       pc = new LocationPatternConverter(formattingInfo,
283                     FILE_LOCATION_CONVERTER);
284       //LogLog.debug("File name converter.");
285
//formattingInfo.dump();
286
currentLiteral.setLength(0);
287       break;
288     case 'l':
289       pc = new LocationPatternConverter(formattingInfo,
290                     FULL_LOCATION_CONVERTER);
291       //LogLog.debug("Location converter.");
292
//formattingInfo.dump();
293
currentLiteral.setLength(0);
294       break;
295     case 'L':
296       pc = new LocationPatternConverter(formattingInfo,
297                     LINE_LOCATION_CONVERTER);
298       //LogLog.debug("LINE NUMBER converter.");
299
//formattingInfo.dump();
300
currentLiteral.setLength(0);
301       break;
302     case 'm':
303       pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
304       //LogLog.debug("MESSAGE converter.");
305
//formattingInfo.dump();
306
currentLiteral.setLength(0);
307       break;
308     case 'M':
309       pc = new LocationPatternConverter(formattingInfo,
310                     METHOD_LOCATION_CONVERTER);
311       //LogLog.debug("METHOD converter.");
312
//formattingInfo.dump();
313
currentLiteral.setLength(0);
314       break;
315     case 'p':
316       pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
317       //LogLog.debug("LEVEL converter.");
318
//formattingInfo.dump();
319
currentLiteral.setLength(0);
320       break;
321     case 'r':
322       pc = new BasicPatternConverter(formattingInfo,
323                      RELATIVE_TIME_CONVERTER);
324       //LogLog.debug("RELATIVE time converter.");
325
//formattingInfo.dump();
326
currentLiteral.setLength(0);
327       break;
328     case 't':
329       pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
330       //LogLog.debug("THREAD converter.");
331
//formattingInfo.dump();
332
currentLiteral.setLength(0);
333       break;
334       /*case 'u':
335       if(i < patternLength) {
336     char cNext = pattern.charAt(i);
337     if(cNext >= '0' && cNext <= '9') {
338       pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
339       LogLog.debug("USER converter ["+cNext+"].");
340       formattingInfo.dump();
341       currentLiteral.setLength(0);
342       i++;
343     }
344     else
345       LogLog.error("Unexpected char" +cNext+" at position "+i);
346       }
347       break;*/

348     case 'x':
349       pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
350       //LogLog.debug("NDC converter.");
351
currentLiteral.setLength(0);
352       break;
353     case 'X':
354       String JavaDoc xOpt = extractOption();
355       pc = new MDCPatternConverter(formattingInfo, xOpt);
356       currentLiteral.setLength(0);
357       break;
358     default:
359       LogLog.error("Unexpected char [" +c+"] at position "+i
360            +" in conversion patterrn.");
361       pc = new LiteralPatternConverter(currentLiteral.toString());
362       currentLiteral.setLength(0);
363     }
364
365     addConverter(pc);
366   }
367
368   protected
369   void addConverter(PatternConverter pc) {
370     currentLiteral.setLength(0);
371     // Add the pattern converter to the list.
372
addToList(pc);
373     // Next pattern is assumed to be a literal.
374
state = LITERAL_STATE;
375     // Reset formatting info
376
formattingInfo.reset();
377   }
378
379   // ---------------------------------------------------------------------
380
// PatternConverters
381
// ---------------------------------------------------------------------
382

383   private static class BasicPatternConverter extends PatternConverter {
384     int type;
385
386     BasicPatternConverter(FormattingInfo formattingInfo, int type) {
387       super(formattingInfo);
388       this.type = type;
389     }
390
391     public
392     String JavaDoc convert(LoggingEvent event) {
393       switch(type) {
394       case RELATIVE_TIME_CONVERTER:
395     return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
396       case THREAD_CONVERTER:
397     return event.getThreadName();
398       case LEVEL_CONVERTER:
399     return event.getLevel().toString();
400       case NDC_CONVERTER:
401     return event.getNDC();
402       case MESSAGE_CONVERTER: {
403     return event.getRenderedMessage();
404       }
405       default: return null;
406       }
407     }
408   }
409
410   private static class LiteralPatternConverter extends PatternConverter {
411     private String JavaDoc literal;
412
413     LiteralPatternConverter(String JavaDoc value) {
414       literal = value;
415     }
416
417     public
418     final
419     void format(StringBuffer JavaDoc sbuf, LoggingEvent event) {
420       sbuf.append(literal);
421     }
422
423     public
424     String JavaDoc convert(LoggingEvent event) {
425       return literal;
426     }
427   }
428
429   private static class DatePatternConverter extends PatternConverter {
430     private DateFormat df;
431     private Date JavaDoc date;
432
433     DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
434       super(formattingInfo);
435       date = new Date JavaDoc();
436       this.df = df;
437     }
438
439     public
440     String JavaDoc convert(LoggingEvent event) {
441       date.setTime(event.timeStamp);
442       String JavaDoc converted = null;
443       try {
444         converted = df.format(date);
445       }
446       catch (Exception JavaDoc ex) {
447         LogLog.error("Error occured while converting date.", ex);
448       }
449       return converted;
450     }
451   }
452
453   private static class MDCPatternConverter extends PatternConverter {
454     private String JavaDoc key;
455
456     MDCPatternConverter(FormattingInfo formattingInfo, String JavaDoc key) {
457       super(formattingInfo);
458       this.key = key;
459     }
460
461     public
462     String JavaDoc convert(LoggingEvent event) {
463       Object JavaDoc val = event.getMDC(key);
464       if(val == null) {
465     return null;
466       } else {
467     return val.toString();
468       }
469     }
470   }
471
472
473   private class LocationPatternConverter extends PatternConverter {
474     int type;
475
476     LocationPatternConverter(FormattingInfo formattingInfo, int type) {
477       super(formattingInfo);
478       this.type = type;
479     }
480
481     public
482     String JavaDoc convert(LoggingEvent event) {
483       LocationInfo locationInfo = event.getLocationInformation();
484       switch(type) {
485       case FULL_LOCATION_CONVERTER:
486     return locationInfo.fullInfo;
487       case METHOD_LOCATION_CONVERTER:
488     return locationInfo.getMethodName();
489       case LINE_LOCATION_CONVERTER:
490     return locationInfo.getLineNumber();
491       case FILE_LOCATION_CONVERTER:
492     return locationInfo.getFileName();
493       default: return null;
494       }
495     }
496   }
497
498   private static abstract class NamedPatternConverter extends PatternConverter {
499     int precision;
500
501     NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
502       super(formattingInfo);
503       this.precision = precision;
504     }
505
506     abstract
507     String JavaDoc getFullyQualifiedName(LoggingEvent event);
508
509     public
510     String JavaDoc convert(LoggingEvent event) {
511       String JavaDoc n = getFullyQualifiedName(event);
512       if(precision <= 0)
513     return n;
514       else {
515     int len = n.length();
516
517     // We substract 1 from 'len' when assigning to 'end' to avoid out of
518
// bounds exception in return r.substring(end+1, len). This can happen if
519
// precision is 1 and the category name ends with a dot.
520
int end = len -1 ;
521     for(int i = precision; i > 0; i--) {
522       end = n.lastIndexOf('.', end-1);
523       if(end == -1)
524         return n;
525     }
526     return n.substring(end+1, len);
527       }
528     }
529   }
530
531   private class ClassNamePatternConverter extends NamedPatternConverter {
532
533     ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
534       super(formattingInfo, precision);
535     }
536
537     String JavaDoc getFullyQualifiedName(LoggingEvent event) {
538       return event.getLocationInformation().getClassName();
539     }
540   }
541
542   private class CategoryPatternConverter extends NamedPatternConverter {
543
544     CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
545       super(formattingInfo, precision);
546     }
547
548     String JavaDoc getFullyQualifiedName(LoggingEvent event) {
549       return event.getLoggerName();
550     }
551   }
552 }
553
554
Popular Tags