/*
* Copyright 2014 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.pinpoint.plugin.jdbc.oracle.parser;
import java.util.ArrayList;
import java.util.List;
/**
* @author emeroad
*/
public class OracleNetConnectionDescriptorTokenizer {
public static final char TOKEN_EQUAL = '=';
public static final char TOKEN_KEY_START = '(';
public static final char TOKEN_KEY_END = ')';
// Connection methodDescriptor can contain below tokens too.
// But we don't support them right now.
private static final char TOKEN_COMMA = ',';
private static final char TOKEN_BKSLASH = '\\';
private static final char TOKEN_DQUOTE = '"';
private static final char TOKEN_SQUOTE = '\'';
public static final int TYPE_KEY_START = 0;
public static final Token TOKEN_KEY_START_OBJECT = new Token(String.valueOf(TOKEN_KEY_START), TYPE_KEY_START);
public static final int TYPE_KEY_END = 1;
public static final Token TOKEN_KEY_END_OBJECT = new Token(String.valueOf(TOKEN_KEY_END), TYPE_KEY_END);
public static final int TYPE_EQUAL = 2;
public static final Token TOKEN_EQUAL_OBJECT = new Token(String.valueOf(TOKEN_EQUAL), TYPE_EQUAL);
public static final int TYPE_LITERAL = 3;
public static final int TYPE_EOF = -1;
public static final Token TOKEN_EOF_OBJECT = new Token("EOF", TYPE_EOF);
private final List<Token> tokenList = new ArrayList<Token>();
private int tokenPosition = 0;
private final String connectionString;
private int position = 0;
public OracleNetConnectionDescriptorTokenizer(String connectionString) {
if (connectionString == null) {
throw new NullPointerException("connectionString");
}
this.connectionString = connectionString;
}
public void parse() {
final int length = connectionString.length();
for (; position < length; position++) {
final char ch = connectionString.charAt(position);
if (isWhiteSpace(ch)) {
continue;
}
switch (ch) {
case TOKEN_KEY_START:
this.tokenList.add(TOKEN_KEY_START_OBJECT);
break;
case TOKEN_EQUAL:
this.tokenList.add(TOKEN_EQUAL_OBJECT);
break;
case TOKEN_KEY_END:
this.tokenList.add(TOKEN_KEY_END_OBJECT);
break;
case TOKEN_COMMA:
case TOKEN_BKSLASH:
case TOKEN_DQUOTE:
case TOKEN_SQUOTE:
// TODO handle these tokens.
// Need to study how these tokens are used.
throw new OracleConnectionStringException("unsupported token:" + ch);
default:
String literal = parseLiteral();
addToken(literal, TYPE_LITERAL);
}
}
this.tokenList.add(TOKEN_EOF_OBJECT);
}
String parseLiteral() {
int start = trimLeft();
for (position = start; position < connectionString.length(); position++) {
final char ch = connectionString.charAt(position);
switch (ch) {
case TOKEN_EQUAL:
case TOKEN_KEY_START:
case TOKEN_KEY_END:
int end = trimRight(position);
// step back position because last seen character is not part of this literal.
position--;
return connectionString.substring(start, end);
default:
}
}
// end of the string.
int end = trimRight(position);
return connectionString.substring(start, end);
}
int trimRight(int index) {
int end = index;
for (; end > 0 ; end--) {
final char ch = connectionString.charAt(end-1);
if (!isWhiteSpace(ch)) {
return end;
}
}
return end;
}
int trimLeft() {
final int length = connectionString.length();
int start = position;
for (; start < length; start++) {
final char ch = connectionString.charAt(start);
if (!isWhiteSpace(ch)) {
return start;
}
}
return start;
}
private void addToken(String tokenString, int type) {
Token token = new Token(tokenString, type);
this.tokenList.add(token);
}
private boolean isWhiteSpace(char ch) {
return (ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r');
}
public Token nextToken() {
if (tokenList.size() <= tokenPosition) {
return null;
}
Token token = tokenList.get(tokenPosition);
tokenPosition++;
return token;
}
public void nextPosition() {
if (tokenList.size() <= tokenPosition) {
return;
}
tokenPosition++;
}
public Token lookAheadToken() {
if (tokenList.size() <= tokenPosition) {
return null;
}
return tokenList.get(tokenPosition);
}
public void setPosition(int position) {
this.position = position;
}
public void checkStartToken() {
Token token = this.nextToken();
if (token == null) {
throw new OracleConnectionStringException("parse error. token is null");
}
// We can check by == because the token object is singleton.
if (!(token == TOKEN_KEY_START_OBJECT)) {
throw new OracleConnectionStringException("syntax error. Expected token='(' :" + token.getToken());
}
}
public void checkEqualToken() {
Token token = this.nextToken();
if (token == null) {
throw new OracleConnectionStringException("parse error. token is null. Expected token='='");
}
// We can check by == because the token object is singleton.
if (!(token == TOKEN_EQUAL_OBJECT)) {
throw new OracleConnectionStringException("Syntax error. Expected token='=' :" + token.getToken());
}
}
public void checkEndToken() {
Token token = this.nextToken();
if (token == null) {
throw new OracleConnectionStringException("parse error. token is null. Expected token=')");
}
// We can check by == because the token object is singleton.
if (!(token == TOKEN_KEY_END_OBJECT)) {
throw new OracleConnectionStringException("Syntax error. Expected token=')' :" + token.getToken());
}
}
public Token getLiteralToken() {
Token token = this.nextToken();
if (token == null) {
throw new OracleConnectionStringException("parse error. token is null. Expected token='LITERAL'");
}
// We can check by == because the token object is singleton.
if (!(token.getType() == TYPE_LITERAL)) {
throw new OracleConnectionStringException("Syntax error. Expected token='LITERAL'' :" + token.getToken());
}
return token;
}
public Token getLiteralToken(String expectedValue) {
Token token = this.nextToken();
if (token == null) {
throw new OracleConnectionStringException("parse error. token is null. Expected token='LITERAL'");
}
// We can check by == because the token object is singleton.
if (!(token.getType() == TYPE_LITERAL)) {
throw new OracleConnectionStringException("Syntax error. Expected token='LITERAL' :" + token.getToken());
}
if (!expectedValue.equals(token.getToken())) {
throw new OracleConnectionStringException("Syntax error. Expected token=" + expectedValue + "' :" + token.getToken());
}
return token;
}
}