/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2015, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core.subst; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.spi.ScanException; import java.util.ArrayList; import java.util.List; public class Tokenizer { enum TokenizerState { LITERAL_STATE, START_STATE, DEFAULT_VAL_STATE } final String pattern; final int patternLength; public Tokenizer(String pattern) { this.pattern = pattern; patternLength = pattern.length(); } TokenizerState state = TokenizerState.LITERAL_STATE; int pointer = 0; List<Token> tokenize() throws ScanException { List<Token> tokenList = new ArrayList<Token>(); StringBuilder buf = new StringBuilder(); while (pointer < patternLength) { char c = pattern.charAt(pointer); pointer++; switch (state) { case LITERAL_STATE: handleLiteralState(c, tokenList, buf); break; case START_STATE: handleStartState(c, tokenList, buf); break; case DEFAULT_VAL_STATE: handleDefaultValueState(c, tokenList, buf); default: } } // EOS switch (state) { case LITERAL_STATE: addLiteralToken(tokenList, buf); break; case DEFAULT_VAL_STATE: // trailing colon. see also LOGBACK-1140 buf.append(CoreConstants.COLON_CHAR); addLiteralToken(tokenList, buf); break; case START_STATE: // trailing $. see also LOGBACK-1149 buf.append(CoreConstants.DOLLAR); addLiteralToken(tokenList, buf); break; } return tokenList; } private void handleDefaultValueState(char c, List<Token> tokenList, StringBuilder stringBuilder) { switch (c) { case CoreConstants.DASH_CHAR: tokenList.add(Token.DEFAULT_SEP_TOKEN); state = TokenizerState.LITERAL_STATE; break; case CoreConstants.DOLLAR: stringBuilder.append(CoreConstants.COLON_CHAR); addLiteralToken(tokenList, stringBuilder); stringBuilder.setLength(0); state = TokenizerState.START_STATE; break; default: stringBuilder.append(CoreConstants.COLON_CHAR).append(c); state = TokenizerState.LITERAL_STATE; break; } } private void handleStartState(char c, List<Token> tokenList, StringBuilder stringBuilder) { if (c == CoreConstants.CURLY_LEFT) { tokenList.add(Token.START_TOKEN); } else { stringBuilder.append(CoreConstants.DOLLAR).append(c); } state = TokenizerState.LITERAL_STATE; } private void handleLiteralState(char c, List<Token> tokenList, StringBuilder stringBuilder) { if (c == CoreConstants.DOLLAR) { addLiteralToken(tokenList, stringBuilder); stringBuilder.setLength(0); state = TokenizerState.START_STATE; } else if (c == CoreConstants.COLON_CHAR) { addLiteralToken(tokenList, stringBuilder); stringBuilder.setLength(0); state = TokenizerState.DEFAULT_VAL_STATE; } else if (c == CoreConstants.CURLY_LEFT) { addLiteralToken(tokenList, stringBuilder); tokenList.add(Token.CURLY_LEFT_TOKEN); stringBuilder.setLength(0); } else if (c == CoreConstants.CURLY_RIGHT) { addLiteralToken(tokenList, stringBuilder); tokenList.add(Token.CURLY_RIGHT_TOKEN); stringBuilder.setLength(0); } else { stringBuilder.append(c); } } private void addLiteralToken(List<Token> tokenList, StringBuilder stringBuilder) { if (stringBuilder.length() == 0) return; tokenList.add(new Token(Token.Type.LITERAL, stringBuilder.toString())); } }