/* * 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; /** * @author emeroad */ public class OracleNetConnectionDescriptorParser { private static String THIN = "jdbc:oracle:thin"; private static String OCI = "jdbc:oracle:oci"; private String url; private String normalizedUrl; private DriverType driverType; private OracleNetConnectionDescriptorTokenizer tokenizer; public OracleNetConnectionDescriptorParser(String url) { this.url = url; this.normalizedUrl = url.toLowerCase(); this.tokenizer = new OracleNetConnectionDescriptorTokenizer(normalizedUrl); } public KeyValue parse() { // You can find driver spec here: http://docs.oracle.com/cd/B14117_01/java.101/b10979/urls.htm // It's for 10g but maybe 11g would be same. int position; if (normalizedUrl.startsWith(THIN)) { position = nextPosition(THIN); driverType = DriverType.THIN; } else if(normalizedUrl.startsWith(OCI)) { position = nextPosition(OCI); driverType = DriverType.OCI; } else { throw new IllegalArgumentException("invalid oracle jdbc url. expected token:(" + THIN + " or " + OCI + ") url:" + url); } // skip thin string this.tokenizer.setPosition(position); this.tokenizer.parse(); KeyValue keyValue = parseKeyValue(); checkEof(); return keyValue; } private void checkEof() { Token eof = this.tokenizer.nextToken(); if (eof == null) { throw new OracleConnectionStringException("parsing error. expected token:'EOF' token:null"); } if (eof != OracleNetConnectionDescriptorTokenizer.TOKEN_EOF_OBJECT) { throw new OracleConnectionStringException("parsing error. expected token:'EOF' token:" + eof); } } public DriverType getDriverType() { return driverType; } private int nextPosition(String driverUrl) { final int thinLength = driverUrl.length(); if (normalizedUrl.startsWith(":@", thinLength)) { return thinLength + 2; } else if(normalizedUrl.startsWith("@", thinLength)) { return thinLength + 1; } else { throw new OracleConnectionStringException("invalid oracle jdbc url:" + driverUrl); } } private KeyValue parseKeyValue() { // start this.tokenizer.checkStartToken(); KeyValue keyValue = new KeyValue(); // key Token literalToken = this.tokenizer.getLiteralToken(); keyValue.setKey(literalToken.getToken()); // = this.tokenizer.checkEqualToken(); // value compare reduce boolean nonTerminalValue = false; while(true) { final Token token = this.tokenizer.lookAheadToken(); if (token == null) { // Abnormal termination. throw new OracleConnectionStringException("Syntax error. lookAheadToken is null"); } if (token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_KEY_START) { nonTerminalValue = true; KeyValue child = parseKeyValue(); keyValue.addKeyValueList(child); // if next token is ')', value is completed. Token endCheck = this.tokenizer.lookAheadToken(); if (endCheck == OracleNetConnectionDescriptorTokenizer.TOKEN_KEY_END_OBJECT) { this.tokenizer.nextPosition(); return keyValue; } } else if(token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_LITERAL) { if (nonTerminalValue) { throw new OracleConnectionStringException("Syntax error. expected token:'(' or ')' :" + token.getToken()); } // We already have checked current token by lookAheadToken(). Proceed to next token. this.tokenizer.nextPosition(); keyValue.setValue(token.getToken()); this.tokenizer.checkEndToken(); return keyValue; } else if(token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_KEY_END){ this.tokenizer.nextPosition(); // This could happen if value is empty. // Does it allow empty value? return keyValue; } else { // Cannot reach here because we checked all those possible cases, START, END and LITERAL. // Adding new token type could cause error. // In case of syntax error, EOF can come to here. throw new OracleConnectionStringException("Syntax error. " + token.getToken()); } } } }