View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, 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.subst;
15  
16  import ch.qos.logback.core.CoreConstants;
17  import ch.qos.logback.core.spi.ScanException;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  public class Tokenizer {
23  
24      enum TokenizerState {
25          LITERAL_STATE, START_STATE, DEFAULT_VAL_STATE
26      }
27  
28      final String pattern;
29      final int patternLength;
30  
31      public Tokenizer(String pattern) {
32          this.pattern = pattern;
33          patternLength = pattern.length();
34      }
35  
36      TokenizerState state = TokenizerState.LITERAL_STATE;
37      int pointer = 0;
38  
39      List<Token> tokenize() throws ScanException {
40          List<Token> tokenList = new ArrayList<Token>();
41          StringBuilder buf = new StringBuilder();
42  
43          while (pointer < patternLength) {
44              char c = pattern.charAt(pointer);
45              pointer++;
46  
47              switch (state) {
48              case LITERAL_STATE:
49                  handleLiteralState(c, tokenList, buf);
50                  break;
51              case START_STATE:
52                  handleStartState(c, tokenList, buf);
53                  break;
54              case DEFAULT_VAL_STATE:
55                  handleDefaultValueState(c, tokenList, buf);
56              default:
57              }
58          }
59          // EOS
60          switch (state) {
61          case LITERAL_STATE:
62              addLiteralToken(tokenList, buf);
63              break;
64          case DEFAULT_VAL_STATE:
65              // trailing colon. see also LOGBACK-1140
66              buf.append(CoreConstants.COLON_CHAR);
67              addLiteralToken(tokenList, buf);
68              break;
69          case START_STATE:
70              // trailing $. see also LOGBACK-1149
71              buf.append(CoreConstants.DOLLAR);
72              addLiteralToken(tokenList, buf);
73              break;
74          }
75          return tokenList;
76      }
77  
78      private void handleDefaultValueState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
79          switch (c) {
80          case CoreConstants.DASH_CHAR:
81              tokenList.add(Token.DEFAULT_SEP_TOKEN);
82              state = TokenizerState.LITERAL_STATE;
83              break;
84          case CoreConstants.DOLLAR:
85              stringBuilder.append(CoreConstants.COLON_CHAR);
86              addLiteralToken(tokenList, stringBuilder);
87              stringBuilder.setLength(0);
88              state = TokenizerState.START_STATE;
89              break;
90          case CoreConstants.CURLY_LEFT:
91              stringBuilder.append(CoreConstants.COLON_CHAR);
92              addLiteralToken(tokenList, stringBuilder);
93              stringBuilder.setLength(0);
94              tokenList.add(Token.CURLY_LEFT_TOKEN);
95              state = TokenizerState.LITERAL_STATE;
96  
97              break;
98          default:
99              stringBuilder.append(CoreConstants.COLON_CHAR).append(c);
100             state = TokenizerState.LITERAL_STATE;
101             break;
102         }
103     }
104 
105     private void handleStartState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
106         if (c == CoreConstants.CURLY_LEFT) {
107             tokenList.add(Token.START_TOKEN);
108         } else {
109             stringBuilder.append(CoreConstants.DOLLAR).append(c);
110         }
111         state = TokenizerState.LITERAL_STATE;
112     }
113 
114     private void handleLiteralState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
115         switch (c) {
116         case CoreConstants.DOLLAR:
117             addLiteralToken(tokenList, stringBuilder);
118             stringBuilder.setLength(0);
119             state = TokenizerState.START_STATE;
120             break;
121         case CoreConstants.COLON_CHAR:
122             addLiteralToken(tokenList, stringBuilder);
123             stringBuilder.setLength(0);
124             state = TokenizerState.DEFAULT_VAL_STATE;
125             break;
126         case CoreConstants.CURLY_LEFT:
127             addLiteralToken(tokenList, stringBuilder);
128             tokenList.add(Token.CURLY_LEFT_TOKEN);
129             stringBuilder.setLength(0);
130             break;
131         case CoreConstants.CURLY_RIGHT:
132             addLiteralToken(tokenList, stringBuilder);
133             tokenList.add(Token.CURLY_RIGHT_TOKEN);
134             stringBuilder.setLength(0);
135             break;
136         default:
137             stringBuilder.append(c);
138         }
139 
140     }
141 
142     private void addLiteralToken(List<Token> tokenList, StringBuilder stringBuilder) {
143         if (stringBuilder.length() == 0)
144             return;
145         tokenList.add(new Token(Token.Type.LITERAL, stringBuilder.toString()));
146     }
147 
148 }