/*
* Copyright 2016 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.spring.boot.interceptor;
import com.navercorp.pinpoint.bootstrap.context.ServerMetaDataHolder;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.plugin.spring.boot.SpringBootConstants;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* @author HyunGil Jeong
*/
public class LauncherLaunchInterceptor implements AroundInterceptor {
private final static String PATH_SEPARATOR = "/";
private final static String JAR_SEPARATOR = "!";
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final TraceContext traceContext;
public LauncherLaunchInterceptor(TraceContext traceContext) {
this.traceContext = traceContext;
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
if (!validate(target, args)) {
return;
}
String serviceName = createServiceName(target);
URLClassLoader classLoader = (URLClassLoader) args[2];
URL[] urls = classLoader.getURLs();
List<String> loadedJarNames = new ArrayList<String>(extractLibJarNamesFromURLs(urls));
ServerMetaDataHolder holder = this.traceContext.getServerMetaDataHolder();
holder.addServiceInfo(serviceName, loadedJarNames);
holder.notifyListeners();
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
// Do nothing
}
private String createServiceName(Object target) {
StringBuilder sb = new StringBuilder(SpringBootConstants.ROOT_CONTEXT_KEY);
sb.append(" (").append(target.getClass().getSimpleName()).append(")");
return sb.toString();
}
private boolean validate(Object target, Object[] args) {
if (target == null || args == null) {
return false;
}
if (args.length < 3) {
return false;
}
if (!(args[2] instanceof URLClassLoader)) {
return false;
}
return true;
}
private Set<String> extractLibJarNamesFromURLs(URL[] urls) {
if (urls == null) {
return Collections.emptySet();
}
Set<String> libJarNames = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
for (URL url : urls) {
try {
String libJarName = extractLibJarName(url);
if (libJarName.length() > 0) {
libJarNames.add(libJarName);
}
} catch (Exception e) {
// safety net
logger.warn("Error extracting library name", e);
}
}
return libJarNames;
}
private String extractLibJarName(URL url) {
String protocol = url.getProtocol();
String path = url.getPath().replaceAll("\\\\", PATH_SEPARATOR);
if (protocol.equals("file")) {
return extractNameFromFile(path);
} else if (protocol.equals("jar")) {
return extractNameFromJar(path);
} else {
return "";
}
}
private String extractNameFromFile(String fileUri) {
int lastIndexOfSeparator = fileUri.lastIndexOf(PATH_SEPARATOR);
if (lastIndexOfSeparator < 0) {
return fileUri;
} else {
return fileUri.substring(lastIndexOfSeparator + 1);
}
}
private String extractNameFromJar(String jarUri) {
String uri = jarUri.substring(0, jarUri.lastIndexOf(JAR_SEPARATOR));
int rootJarEndIndex = uri.indexOf(JAR_SEPARATOR);
if (rootJarEndIndex < 0) {
return extractNameFromFile(uri);
}
String rootJarFileUri = extractNameFromFile(uri.substring(0, rootJarEndIndex));
StringBuilder sb = new StringBuilder(rootJarFileUri);
sb.append(uri.substring(rootJarEndIndex));
return sb.toString();
}
}