View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.pattern.parser;
15  
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  import ch.qos.logback.core.CoreConstants;
21  import ch.qos.logback.core.pattern.Converter;
22  import ch.qos.logback.core.pattern.FormatInfo;
23  import ch.qos.logback.core.pattern.IdentityCompositeConverter;
24  import ch.qos.logback.core.pattern.ReplacingCompositeConverter;
25  import ch.qos.logback.core.pattern.util.IEscapeUtil;
26  import ch.qos.logback.core.pattern.util.RegularEscapeUtil;
27  import ch.qos.logback.core.spi.ContextAwareBase;
28  
29  // ~=lamda
30  // E = TE|T
31  
32  // Left factorization
33  // E = T(E|~)
34  // Eopt = E|~
35  // replace E|~ with Eopt in E
36  // E = TEopt
37  
38  // T = LITERAL | '%' C | '%' FORMAT_MODIFIER C
39  // C = SIMPLE_KEYWORD OPTION | COMPOSITE_KEYWORD COMPOSITE
40  // OPTION = {...} | ~
41  // COMPOSITE = E ')' OPTION
42  
43  
44  
45  public class Parser<E> extends ContextAwareBase {
46  
47    public final static String MISSING_RIGHT_PARENTHESIS = CoreConstants.CODES_URL+"#missingRightParenthesis";
48    public final static Map<String, String> DEFAULT_COMPOSITE_CONVERTER_MAP = new HashMap<String, String>();
49    public final static String REPLACE_CONVERTER_WORD = "replace";
50    static {
51      DEFAULT_COMPOSITE_CONVERTER_MAP.put(Token.BARE_COMPOSITE_KEYWORD_TOKEN.getValue().toString(),
52              IdentityCompositeConverter.class.getName());
53      DEFAULT_COMPOSITE_CONVERTER_MAP.put(REPLACE_CONVERTER_WORD,
54               ReplacingCompositeConverter.class.getName());
55    }
56  
57    final List tokenList;
58    int pointer = 0;
59    
60    Parser(TokenStream ts) throws ScanException {
61      this.tokenList = ts.tokenize();
62    }
63  
64    public Parser(String pattern) throws ScanException {
65      this(pattern, new RegularEscapeUtil());
66    }
67    
68    public Parser(String pattern, IEscapeUtil escapeUtil) throws ScanException {
69      try {
70        TokenStream ts = new TokenStream(pattern, escapeUtil);
71        this.tokenList = ts.tokenize();
72      } catch (IllegalArgumentException npe) {
73        throw new ScanException("Failed to initialize Parser", npe);
74      }
75    }
76  
77    /**
78     * When the parsing step is done, the Node list can be transformed into a
79     * converter chain.
80     *
81     * @param top
82     * @param converterMap
83     * @return
84     * @throws ScanException
85     */
86    public Converter<E> compile(final Node top, Map converterMap) {
87      Compiler<E> compiler = new Compiler<E>(top, converterMap);
88      compiler.setContext(context);
89      //compiler.setStatusManager(statusManager);
90      return compiler.compile();
91    }
92  
93    public Node parse() throws ScanException {
94      return E();
95    }
96  
97    // E = TEopt
98    Node E() throws ScanException {
99      Node t = T();
100     if (t == null) {
101       return null;
102     }
103     Node eOpt = Eopt();
104     if (eOpt != null) {
105       t.setNext(eOpt);
106     }
107     return t;
108   }
109 
110   // Eopt = E|~
111   Node Eopt() throws ScanException {
112     // System.out.println("in Eopt()");
113     Token next = getCurentToken();
114     // System.out.println("Current token is " + next);
115     if (next == null) {
116       return null;
117     } else {
118       return E();
119     }
120   }
121 
122   // T = LITERAL | '%' C | '%' FORMAT_MODIFIER C
123   Node T() throws ScanException {
124     Token t = getCurentToken();
125     expectNotNull(t, "a LITERAL or '%'");
126 
127     switch (t.getType()) {
128     case Token.LITERAL:
129       advanceTokenPointer();
130       return new Node(Node.LITERAL, t.getValue());
131     case Token.PERCENT:
132       advanceTokenPointer();
133       // System.out.println("% token found");
134       FormatInfo fi;
135       Token u = getCurentToken();
136       FormattingNode c;
137       expectNotNull(u, "a FORMAT_MODIFIER, SIMPLE_KEYWORD or COMPOUND_KEYWORD");
138       if (u.getType() == Token.FORMAT_MODIFIER) {
139         fi = FormatInfo.valueOf((String) u.getValue());
140         advanceTokenPointer();
141         c = C();
142         c.setFormatInfo(fi);
143       } else {
144         c = C();
145       }
146       return c;
147 
148     default:
149       return null;
150 
151     }
152 
153   }
154 
155   FormattingNode C() throws ScanException {
156     Token t = getCurentToken();
157     // System.out.println("in C()");
158     // System.out.println("Current token is " + t);
159     expectNotNull(t, "a LEFT_PARENTHESIS or KEYWORD");
160     int type = t.getType();
161     switch (type) {
162     case Token.SIMPLE_KEYWORD:
163       return SINGLE();
164     case Token.COMPOSITE_KEYWORD:
165       advanceTokenPointer();
166       return COMPOSITE(t.getValue().toString());
167     default:
168       throw new IllegalStateException("Unexpected token " + t);
169     }
170   }
171 
172   FormattingNode SINGLE() throws ScanException {
173     // System.out.println("in SINGLE()");
174     Token t = getNextToken();
175     // System.out.println("==" + t);
176     SimpleKeywordNode keywordNode = new SimpleKeywordNode(t.getValue());
177 
178     Token ot = getCurentToken();
179     if (ot != null && ot.getType() == Token.OPTION) {
180       List<String> optionList = (List<String>) ot.getValue();
181       keywordNode.setOptions(optionList);
182       advanceTokenPointer();
183     }
184     return keywordNode;
185   }
186 
187   FormattingNode COMPOSITE(String keyword) throws ScanException {
188     CompositeNode compositeNode = new CompositeNode(keyword);
189 
190     Node childNode = E();
191     compositeNode.setChildNode(childNode);
192 
193     Token t = getNextToken();
194 
195     if (t == null || t.getType() != Token.RIGHT_PARENTHESIS) {
196         String msg = "Expecting RIGHT_PARENTHESIS token but got " + t;
197         addError(msg);
198         addError("See also "+MISSING_RIGHT_PARENTHESIS);
199         throw new ScanException(msg);
200     }
201     Token ot = getCurentToken();
202     if (ot != null && ot.getType() == Token.OPTION) {
203       List<String> optionList = (List<String>) ot.getValue();
204       compositeNode.setOptions(optionList);
205       advanceTokenPointer();
206     }
207     return compositeNode;
208   }
209 
210   Token getNextToken() {
211     if (pointer < tokenList.size()) {
212       return (Token) tokenList.get(pointer++);
213     }
214     return null;
215   }
216 
217   Token getCurentToken() {
218     if (pointer < tokenList.size()) {
219       return (Token) tokenList.get(pointer);
220     }
221     return null;
222   }
223 
224   void advanceTokenPointer() {
225     pointer++;
226   }
227 
228   void expectNotNull(Token t, String expected) {
229     if (t == null) {
230       throw new IllegalStateException("All tokens consumed but was expecting "
231           + expected);
232     }
233   }
234 
235 //  public void setStatusManager(StatusManager statusManager) {
236 //    this.statusManager = statusManager;
237 //  }
238 }