Skip to content

Commit

Permalink
[#9653] Add plugin package class requirement filter
Browse files Browse the repository at this point in the history
  • Loading branch information
donghun-cho committed Jan 25, 2023
1 parent 1ffb662 commit 882c3be
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 27 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@

<javax.servlet4.version>4.0.1</javax.servlet4.version>
<javax.servlet.version>3.0.1</javax.servlet.version>
<jakarta.servlet.version>5.0.0</jakarta.servlet.version>


<asm.version>9.4</asm.version>
Expand Down Expand Up @@ -1025,6 +1026,12 @@
<version>${javax.servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${jakarta.servlet.version}</version>
<scope>provided</scope>
</dependency>


<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.navercorp.pinpoint.profiler.instrument.classloading;

import com.navercorp.pinpoint.common.profiler.concurrent.jsr166.ConcurrentWeakHashMap;
import java.util.Objects;
import com.navercorp.pinpoint.exception.PinpointException;
import com.navercorp.pinpoint.profiler.instrument.classreading.SimpleClassMetadata;
import com.navercorp.pinpoint.profiler.instrument.classreading.SimpleClassMetadataReader;
Expand All @@ -27,14 +26,15 @@
import com.navercorp.pinpoint.profiler.util.FileBinary;
import com.navercorp.pinpoint.profiler.util.JarReader;
import com.navercorp.pinpoint.profiler.util.JavaAssistUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

Expand Down Expand Up @@ -107,6 +107,9 @@ private boolean isPluginPackage(String className) {
return pluginConfig.getPluginPackageFilter().accept(className);
}

private boolean isPluginPackageRequirementMeet(String className) {
return pluginConfig.getPluginPackageRequirementFilter().accept(className);
}

private Class<?> injectClass0(ClassLoader classLoader, String className) throws IllegalArgumentException {
if (isDebug) {
Expand All @@ -133,7 +136,7 @@ private InputStream getPluginInputStream(String classPath) throws IllegalArgumen
}
try {
return pluginJarReader.getInputStream(classPath);
} catch(Exception ex) {
} catch (Exception ex) {
if (isDebug) {
logger.debug("Failed to read plugin jar: {}", pluginConfig.getPluginJarURLExternalForm(), ex);
}
Expand Down Expand Up @@ -207,11 +210,12 @@ private void defineJarClass(ClassLoader classLoader, ClassLoaderAttachment attac
Map<String, SimpleClassMetadata> classEntryMap = parse(fileBinaryList);

for (Map.Entry<String, SimpleClassMetadata> entry : classEntryMap.entrySet()) {

final SimpleClassMetadata classMetadata = entry.getValue();
ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker();
classLoadingChecker.isFirstLoad(classMetadata.getClassName());
define0(classLoader, attachment, classMetadata, classEntryMap, classLoadingChecker);
if (isPluginPackageRequirementMeet(classMetadata.getClassName())) {
ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker();
classLoadingChecker.isFirstLoad(classMetadata.getClassName());
define0(classLoader, attachment, classMetadata, classEntryMap, classLoadingChecker);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginGlobalContext;
import com.navercorp.pinpoint.common.trace.ServiceType;
import java.util.Objects;
import com.navercorp.pinpoint.common.util.CodeSourceUtils;
import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector;
import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjectorFactory;
import com.navercorp.pinpoint.profiler.plugin.config.PluginLoadingConfig;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.net.URL;
import java.util.ArrayList;
Expand All @@ -34,10 +33,10 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* @author Jongho Moon
*
*/
public class DefaultProfilerPluginContextLoader implements ProfilerPluginContextLoader {
private final Logger logger = LogManager.getLogger(getClass());
Expand Down Expand Up @@ -85,18 +84,21 @@ public PluginsSetupResult load(List<ProfilerPlugin> profilerPlugins) {

private List<PluginSetupResult> setupPlugin(ProfilerPluginGlobalContext globalContext, JarPlugin<ProfilerPlugin> plugin) {
List<String> pluginPackageList = plugin.getPackageList();
List<String> pluginPackageRequirementList = plugin.getPackageRequirementList();
final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList);
final ClassNameFilter pluginPackageRequirementFilter = createPluginRequirementFilterChain(pluginPackageRequirementList);

List<ProfilerPlugin> filterProfilerPlugin = filterProfilerPlugin(plugin.getInstanceList(), pluginLoadingConfig.getDisabledPlugins());

List<PluginSetupResult> result = new ArrayList<>();
for (ProfilerPlugin profilerPlugin : filterProfilerPlugin) {
if (logger.isInfoEnabled()) {
logger.info("{} Plugin {}:{}", profilerPlugin.getClass(), PluginJar.PINPOINT_PLUGIN_PACKAGE, pluginPackageList);
logger.info("{} Requirements {}:{}", profilerPlugin.getClass(), PluginJar.PINPOINT_PLUGIN_PACKAGE_CLASS_REQUIREMENTS, pluginPackageRequirementList);
logger.info("Loading plugin:{} pluginPackage:{}", profilerPlugin.getClass().getName(), profilerPlugin);
}

PluginConfig pluginConfig = new PluginConfig(plugin, pluginFilterChain);
PluginConfig pluginConfig = new PluginConfig(plugin, pluginFilterChain, pluginPackageRequirementFilter);
final ClassInjector classInjector = classInjectorFactory.newClassInjector(pluginConfig);
final PluginSetupResult setupResult = pluginSetup.setupPlugin(globalContext, profilerPlugin, classInjector);
result.add(setupResult);
Expand Down Expand Up @@ -129,6 +131,10 @@ private ClassNameFilter createPluginFilterChain(List<String> packageList) {
return filterChain;
}

private ClassNameFilter createPluginRequirementFilterChain(List<String> packageRequirementList) {
return new PluginPackageClassRequirementFilter(packageRequirementList);
}

private static class JarPluginComponents {

private final Logger logger = LogManager.getLogger(this.getClass());
Expand Down Expand Up @@ -186,7 +192,7 @@ private void addProfilerPlugin(ProfilerPlugin profilerPlugin) {
}

private JarPlugin<ProfilerPlugin> toJarPlugin() {
return new JarPlugin<>(pluginJar, profilerPlugins, pluginJar.getPluginPackages());
return new JarPlugin<>(pluginJar, profilerPlugins, pluginJar.getPluginPackages(), pluginJar.getPluginPackageRequirements());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
package com.navercorp.pinpoint.profiler.plugin;

import java.net.URL;
import java.util.Objects;

import java.util.List;
import java.util.Objects;
import java.util.jar.JarFile;

/**
Expand All @@ -31,11 +30,13 @@ public class JarPlugin<T> implements Plugin<T> {

private final List<T> instanceList;
private final List<String> packageList;
private final List<String> packageRequirementList;

public JarPlugin(PluginJar pluginJar, List<T> instanceList, List<String> packageList) {
public JarPlugin(PluginJar pluginJar, List<T> instanceList, List<String> packageList, List<String> packageRequirementList) {
this.pluginJar = Objects.requireNonNull(pluginJar, "pluginJar");
this.instanceList = Objects.requireNonNull(instanceList, "instanceList");
this.packageList = Objects.requireNonNull(packageList, "packageList");
this.packageRequirementList = Objects.requireNonNull(packageRequirementList, "packageRequirementList");
}

@Override
Expand All @@ -53,6 +54,11 @@ public List<String> getPackageList() {
return packageList;
}

@Override
public List<String> getPackageRequirementList() {
return packageRequirementList;
}

public JarFile getJarFile() {
return pluginJar.getJarFile();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ public interface Plugin<T> {
List<T> getInstanceList();

List<String> getPackageList();

List<String> getPackageRequirementList();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

import java.net.URL;
import java.util.Objects;


import java.util.jar.JarFile;

/**
Expand All @@ -29,12 +27,14 @@ public class PluginConfig {

private final JarPlugin<?> plugin;
private final ClassNameFilter pluginPackageFilter;
private final ClassNameFilter pluginPackageRequirementFilter;

private String pluginJarURLExternalForm;

public PluginConfig(Plugin<?> plugin, ClassNameFilter pluginPackageFilter) {
public PluginConfig(Plugin<?> plugin, ClassNameFilter pluginPackageFilter, ClassNameFilter pluginPackageRequirementFilter) {
this.plugin = cast(plugin);
this.pluginPackageFilter = pluginPackageFilter;
this.pluginPackageRequirementFilter = pluginPackageRequirementFilter;
}

private JarPlugin<?> cast(Plugin<?> plugin) {
Expand Down Expand Up @@ -65,6 +65,10 @@ public ClassNameFilter getPluginPackageFilter() {
return pluginPackageFilter;
}

public ClassNameFilter getPluginPackageRequirementFilter() {
return pluginPackageRequirementFilter;
}

@Override
public String toString() {
return "PluginConfig{" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@
package com.navercorp.pinpoint.profiler.plugin;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Objects;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarFile;

/**
Expand All @@ -34,6 +33,7 @@ public class PluginJar {
public static final String PINPOINT_PLUGIN_PACKAGE = "Pinpoint-Plugin-Package";
public static final String PINPOINT_PLUGIN_COMPILER_VERSION = "Pinpoint-Plugin-Compiler-Version";
public static final String DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME = "com.navercorp.pinpoint.plugin";
public static final String PINPOINT_PLUGIN_PACKAGE_CLASS_REQUIREMENTS = "Pinpoint-Plugin-Package-Class-Requirements";

private final URL url;
private final JarFile jarFile;
Expand Down Expand Up @@ -102,6 +102,10 @@ public List<String> getPluginPackages() {
return manifest.getPluginPackages();
}

public List<String> getPluginPackageRequirements() {
return manifest.getPluginPackageRequirements();
}

@Override
public String toString() {
return "PluginJar{" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ public class PluginManifest {
private final String pluginId;
private final String pluginCompilerVersion;
private final List<String> pluginPackages;
private final List<String> pluginPackageRequirements;

public PluginManifest(String pluginId, String pluginCompilerVersion, List<String> pluginPackages) {
public PluginManifest(String pluginId, String pluginCompilerVersion, List<String> pluginPackages, List<String> pluginPackageRequirements) {
this.pluginId = pluginId;
this.pluginCompilerVersion = pluginCompilerVersion;
this.pluginPackages = pluginPackages;
this.pluginPackageRequirements = pluginPackageRequirements;
}

public static PluginManifest of(JarFile jarFile) {
Expand All @@ -45,13 +47,16 @@ public static PluginManifest of(JarFile jarFile) {
final Attributes mainAttributes = manifest.getMainAttributes();

String pluginId = JarFileUtils.getValue(mainAttributes, PluginJar.PINPOINT_PLUGIN_ID, null);
String pluginCompilerVersion = JarFileUtils.getValue(mainAttributes, PluginJar.PINPOINT_PLUGIN_COMPILER_VERSION, null);
String pluginCompilerVersion = JarFileUtils.getValue(mainAttributes, PluginJar.PINPOINT_PLUGIN_COMPILER_VERSION, null);

String pluginPackages = JarFileUtils.getValue(mainAttributes, PluginJar.PINPOINT_PLUGIN_PACKAGE, PluginJar.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME);

List<String> pluginPackageList = StringUtils.tokenizeToStringList(pluginPackages, ",");

return new PluginManifest(pluginId, pluginCompilerVersion, pluginPackageList);
String pluginPackageRequirements = JarFileUtils.getValue(mainAttributes, PluginJar.PINPOINT_PLUGIN_PACKAGE_CLASS_REQUIREMENTS, "");
List<String> pluginPackageRequirementList = StringUtils.tokenizeToStringList(pluginPackageRequirements, ",");

return new PluginManifest(pluginId, pluginCompilerVersion, pluginPackageList, pluginPackageRequirementList);
}

private static Manifest getManifest(JarFile jarFile) {
Expand All @@ -74,6 +79,10 @@ public List<String> getPluginPackages() {
return pluginPackages;
}

public List<String> getPluginPackageRequirements() {
return pluginPackageRequirements;
}

@Override
public String toString() {
return "PluginManifest{" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.navercorp.pinpoint.profiler.plugin;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class PluginPackageClassRequirementFilter implements ClassNameFilter {

private final String[] packages;
private final String[] requirements;
private final Logger logger = LogManager.getLogger(this.getClass());

public PluginPackageClassRequirementFilter(List<String> packageRequirementList) {
Objects.requireNonNull(packageRequirementList, "packageRequirementList");

final List<String> packageList = new ArrayList<>();
final List<String> requirementList = new ArrayList<>();
for (String packageWithRequirement : packageRequirementList) {
String[] split = packageWithRequirement.split(":");
packageList.add(split[0]);
requirementList.add(split[1]);
}

packages = packageList.toArray(new String[0]);
requirements = requirementList.toArray(new String[0]);
}

@Override
public boolean accept(String className) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
for (int i = 0; i < packages.length; i++) {
if (className.startsWith(packages[i])) {
if (!isLoadedClass(requirements[i], cl)) {
if (logger.isDebugEnabled()) {
logger.debug("reject class:{}, packageName:{}, requirement:{}, classloader:{}", className, packages[i], requirements[i], cl);
}
return REJECT;
}
}
}
return ACCEPT;
}

private boolean isLoadedClass(String classname, ClassLoader cl) {
try {
Class.forName(classname, false, cl);
return true;
} catch (ClassNotFoundException ignored) {
}
return false;
}

@Override
public String toString() {
return "PluginPackageRequirementFilter{" +
"packages=" + Arrays.toString(packages) +
", requirements=" + Arrays.toString(requirements) +
'}';
}
}
Loading

0 comments on commit 882c3be

Please # to comment.