/*
* 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.common.server.util;
import com.navercorp.pinpoint.common.util.ApiDescription;
import com.navercorp.pinpoint.common.util.DefaultApiDescription;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import java.util.regex.Pattern;
/**
* Similar to MethodDescriptor, but instead parses string-based values.
* @author emeroad
*/
public class ApiDescriptionParser {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final char DOT = '.';
private static final char METHOD_PARAM_START = '(';
private static final char METHOD_PARAM_END = ')';
private static final char PARAMETER_SP = ',';
private static Pattern PARAMETER_REGEX = Pattern.compile(", |,");
// org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
// com.mysql.jdbc.ConnectionImpl.setAutoCommit(boolean autoCommitFlag)
// com.mysql.jdbc.ConnectionImpl.commit()
// org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request request, org.apache.catalina.connector.Response response):110
public ApiDescription parse(String apiDescriptionString) {
if (apiDescriptionString == null) {
throw new NullPointerException("apiDescriptionString must not be null");
}
final int methodStart = apiDescriptionString.lastIndexOf(METHOD_PARAM_START);
if (methodStart == -1) {
throw new IllegalArgumentException("'(' not found. invalid apiDescriptionString:" + apiDescriptionString);
}
final int methodEnd = apiDescriptionString.lastIndexOf(METHOD_PARAM_END);
if (methodEnd == -1) {
throw new IllegalArgumentException("')' not found. invalid apiDescriptionString:" + apiDescriptionString);
}
final int classIndex = apiDescriptionString.lastIndexOf(DOT, methodStart);
if (classIndex == -1) {
throw new IllegalArgumentException("'.' not found. invalid apiDescriptionString:" + apiDescriptionString);
}
String className = parseClassName(apiDescriptionString, classIndex);
ApiDescription api = new DefaultApiDescription();
api.setClassName(className);
String methodName = parseMethodName(apiDescriptionString, methodStart, classIndex);
api.setMethodName(methodName);
String parameterDescriptor = apiDescriptionString.substring(methodStart + 1, methodEnd);
String[] parameterList = parseParameter(parameterDescriptor);
String[] simpleParameterList = parseSimpleParameter(parameterList);
api.setSimpleParameter(simpleParameterList);
int lineIndex = apiDescriptionString.lastIndexOf(':');
// TODO for now, check and display the lineNumber
if (lineIndex != -1) {
try {
int line = Integer.parseInt(apiDescriptionString.substring(lineIndex + 1, apiDescriptionString.length()));
api.setLine(line);
} catch (NumberFormatException e) {
LoggerFactory.getLogger(this.getClass()).warn("line number parse error {}", e);
}
}
return api;
}
private String[] parseSimpleParameter(String[] parameterList) {
if (ArrayUtils.isEmpty(parameterList)) {
return EMPTY_STRING_ARRAY;
}
String[] simple = new String[parameterList.length];
for (int i = 0; i < parameterList.length; i++) {
simple[i] = simpleParameter(parameterList[i]);
}
return simple;
}
private String simpleParameter(String parameter) {
int packageIndex = parameter.lastIndexOf(DOT);
if (packageIndex == -1) {
// same logic as below (-1 + 1 == 0) - explicitly checks as there may be changes in the future.
packageIndex = 0;
} else {
packageIndex += 1;
}
return parameter.substring(packageIndex, parameter.length());
}
private String[] parseParameter(String parameterDescriptor) {
if (StringUtils.isEmpty(parameterDescriptor)) {
return EMPTY_STRING_ARRAY;
}
return PARAMETER_REGEX.split(parameterDescriptor);
}
private String parseClassName(String apiDescriptionString, int classIndex) {
return apiDescriptionString.substring(0, classIndex);
}
private String parseMethodName(String apiDescriptionString, int methodStart, int classIndex) {
return apiDescriptionString.substring(classIndex + 1, methodStart);
}
}