001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.subst; 015 016import ch.qos.logback.core.CoreConstants; 017import ch.qos.logback.core.spi.ScanException; 018 019import java.util.ArrayList; 020import java.util.List; 021 022public class Tokenizer { 023 024 enum TokenizerState { 025 LITERAL_STATE, START_STATE, DEFAULT_VAL_STATE 026 } 027 028 final String pattern; 029 final int patternLength; 030 031 public Tokenizer(String pattern) { 032 this.pattern = pattern; 033 patternLength = pattern.length(); 034 } 035 036 TokenizerState state = TokenizerState.LITERAL_STATE; 037 int pointer = 0; 038 039 List<Token> tokenize() throws ScanException { 040 List<Token> tokenList = new ArrayList<Token>(); 041 StringBuilder buf = new StringBuilder(); 042 043 while (pointer < patternLength) { 044 char c = pattern.charAt(pointer); 045 pointer++; 046 047 switch (state) { 048 case LITERAL_STATE: 049 handleLiteralState(c, tokenList, buf); 050 break; 051 case START_STATE: 052 handleStartState(c, tokenList, buf); 053 break; 054 case DEFAULT_VAL_STATE: 055 handleDefaultValueState(c, tokenList, buf); 056 default: 057 } 058 } 059 // EOS 060 switch (state) { 061 case LITERAL_STATE: 062 addLiteralToken(tokenList, buf); 063 break; 064 case DEFAULT_VAL_STATE: 065 // trailing colon. see also LOGBACK-1140 066 buf.append(CoreConstants.COLON_CHAR); 067 addLiteralToken(tokenList, buf); 068 break; 069 case START_STATE: 070 // trailing $. see also LOGBACK-1149 071 buf.append(CoreConstants.DOLLAR); 072 addLiteralToken(tokenList, buf); 073 break; 074 } 075 return tokenList; 076 } 077 078 private void handleDefaultValueState(char c, List<Token> tokenList, StringBuilder stringBuilder) { 079 switch (c) { 080 case CoreConstants.DASH_CHAR: 081 tokenList.add(Token.DEFAULT_SEP_TOKEN); 082 state = TokenizerState.LITERAL_STATE; 083 break; 084 case CoreConstants.DOLLAR: 085 stringBuilder.append(CoreConstants.COLON_CHAR); 086 addLiteralToken(tokenList, stringBuilder); 087 stringBuilder.setLength(0); 088 state = TokenizerState.START_STATE; 089 break; 090 case CoreConstants.CURLY_LEFT: 091 stringBuilder.append(CoreConstants.COLON_CHAR); 092 addLiteralToken(tokenList, stringBuilder); 093 stringBuilder.setLength(0); 094 tokenList.add(Token.CURLY_LEFT_TOKEN); 095 state = TokenizerState.LITERAL_STATE; 096 097 break; 098 default: 099 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}