From 339ca28bb2cd52f23f3da343b34454417025559d Mon Sep 17 00:00:00 2001 From: Woonduk Kang Date: Fri, 29 Jan 2016 21:17:34 +0900 Subject: [PATCH] refactoring api add testcase --- .../BootstrapClassLoaderHandler.java | 89 +++++++++ .../JarProfilerPluginClassInjector.java | 182 ++--------------- .../instrument/PlainClassLoaderHandler.java | 186 ++++++++++++++++++ .../instrument/URLClassLoaderHandler.java | 122 ++++++++++++ .../profiler/plugin/ClassNameFilterChain.java | 47 +++++ .../PinpointProfilerPackageSkipFilter.java | 74 +++++++ .../profiler/plugin/PluginConfig.java | 41 +--- .../profiler/plugin/ProfilerPluginLoader.java | 82 +++++++- .../JarProfilerPluginClassInjectorTest.java | 129 ++++++++++++ .../plugin/ClassNameFilterChainTest.java | 43 ++++ ...PinpointProfilerPackageSkipFilterTest.java | 37 ++++ .../plugin/PluginPackageFilterTest.java | 40 ++++ 12 files changed, 861 insertions(+), 211 deletions(-) create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapClassLoaderHandler.java create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/PlainClassLoaderHandler.java create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/URLClassLoaderHandler.java create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilter.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjectorTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChainTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilterTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PluginPackageFilterTest.java diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapClassLoaderHandler.java new file mode 100644 index 000000000..91be6fb7a --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapClassLoaderHandler.java @@ -0,0 +1,89 @@ +/* + * * + * * 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. + * + */ + +/* + * * + * * 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.profiler.instrument; + +import com.navercorp.pinpoint.exception.PinpointException; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BootstrapClassLoaderHandler implements ClassInjector { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final PluginConfig pluginConfig; + + private final Object lock = new Object(); + private boolean injectedToRoot = false; + + public BootstrapClassLoaderHandler(PluginConfig pluginConfig) { + if (pluginConfig == null) { + throw new NullPointerException("pluginConfig must not be null"); + } + this.pluginConfig = pluginConfig; + } + + @Override + @SuppressWarnings("unchecked") + public Class injectClass(ClassLoader classLoader, String className) { + try { + if (classLoader == null) { + return (Class)injectClass0(className); + } + } catch (Exception e) { + logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); + throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e); + } + throw new PinpointException("invalid ClassLoader"); + } + + private Class injectClass0(String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + synchronized (lock) { + if (this.injectedToRoot == false) { + this.injectedToRoot = true; + pluginConfig.getInstrumentation().appendToBootstrapClassLoaderSearch(pluginConfig.getPluginJarFile()); + pluginConfig.getClassPool().appendToBootstrapClassPath(pluginConfig.getPluginJarFile().getName()); + } + } + return Class.forName(className, false, null); + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjector.java index 1733f61f1..565ac8031 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjector.java @@ -3,9 +3,9 @@ * 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. @@ -14,20 +14,9 @@ */ package com.navercorp.pinpoint.profiler.instrument; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; import java.net.URLClassLoader; -import java.util.*; -import com.navercorp.pinpoint.profiler.plugin.ClassLoadingChecker; import com.navercorp.pinpoint.profiler.plugin.PluginConfig; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.LoaderClassPath; -import javassist.NotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,37 +29,18 @@ import com.navercorp.pinpoint.exception.PinpointException; */ public class JarProfilerPluginClassInjector implements ClassInjector { private final Logger logger = LoggerFactory.getLogger(JarProfilerPluginClassInjector.class); - private final boolean isDebug = logger.isDebugEnabled(); - private static final Method ADD_URL; - private static final Method DEFINE_CLASS; - - static { - try { - ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - ADD_URL.setAccessible(true); - } catch (Exception e) { - throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e); - } - - try { - DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - DEFINE_CLASS.setAccessible(true); - } catch (Exception e) { - throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e); - } - } - - private final PluginConfig pluginConfig; - - private final Object lock = new Object(); - private boolean injectedToRoot = false; + private final ClassInjector bootstrapClassLoaderHandler; + private final ClassInjector urlClassLoaderHandler; + private final ClassInjector plainClassLoaderHandler; public JarProfilerPluginClassInjector(PluginConfig pluginConfig) { if (pluginConfig == null) { throw new NullPointerException("pluginConfig must not be null"); } - this.pluginConfig = pluginConfig; + this.bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig); + this.urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig); + this.plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig); } @Override @@ -78,12 +48,12 @@ public class JarProfilerPluginClassInjector implements ClassInjector { public Class injectClass(ClassLoader classLoader, String className) { try { if (classLoader == null) { - return (Class)injectToBootstrapClassLoader(className); + return (Class)bootstrapClassLoaderHandler.injectClass(null, className); } else if (classLoader instanceof URLClassLoader) { final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; - return (Class)injectToURLClassLoader(urlClassLoader, className); + return (Class)urlClassLoaderHandler.injectClass(urlClassLoader, className); } else { - return (Class)injectToPlainClassLoader(classLoader, className); + return (Class)plainClassLoaderHandler.injectClass(classLoader, className); } } catch (Exception e) { logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); @@ -91,134 +61,4 @@ public class JarProfilerPluginClassInjector implements ClassInjector { } } - private Class injectToBootstrapClassLoader(String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { - synchronized (lock) { - if (this.injectedToRoot == false) { - this.injectedToRoot = true; - pluginConfig.getInstrumentation().appendToBootstrapClassLoaderSearch(pluginConfig.getPluginJarFile()); - pluginConfig.getClassPool().appendToBootstrapClassPath(pluginConfig.getPluginJarFile().getName()); - } - } - - return Class.forName(className, false, null); - } - - private Class injectToURLClassLoader(URLClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { - final URL[] urls = classLoader.getURLs(); - if (urls != null) { - - boolean hasPluginJar = false; - for (URL url : urls) { - // if (url.equals(pluginJarURL)) { fix very slow - // http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html - final String externalForm = url.toExternalForm(); - if (pluginConfig.getPluginJarURLExternalForm().equals(externalForm)) { - hasPluginJar = true; - break; - } - } - - if (!hasPluginJar) { - ADD_URL.invoke(classLoader, pluginConfig.getPluginJar()); - } - } - - return classLoader.loadClass(className); - } - - private Class injectToPlainClassLoader(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException { - if (isDebug) { - logger.debug("injectToPlainClassLoader className:{} cl:{}", className, classLoader); - } - logger.info("bootstrapCoreJarPath:{}", pluginConfig.getBootstrapCoreJarPath()); - - final ClassPool pool = createClassPool(classLoader); - - // TODO ClassLoader + ClassName key? - // TODO concurrent class loading - final ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker(); - return injectToPlainClassLoader(pool, classLoader, className, classLoadingChecker); - } - - private ClassPool createClassPool(ClassLoader classLoader) throws NotFoundException { - final ClassPool pool = new ClassPool(); - pool.appendClassPath(pluginConfig.getBootstrapCoreJarPath()); - - pool.appendClassPath(new LoaderClassPath(classLoader)); - pool.appendClassPath(pluginConfig.getPluginJarFile().getName()); - return pool; - } - - private Class injectToPlainClassLoader(ClassPool pool, ClassLoader classLoader, String className, ClassLoadingChecker classLoadingChecker) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { - if (pluginConfig.getProfilerPackageFilter().accept(className)) { - if (isDebug) { - logger.debug("ProfilerFilter skip class {}", className); - } - return null; - } - if (!pluginConfig.getPluginPackageFilter().accept(className)) { - if (isDebug) { - logger.debug("PluginFilter skip class:{}", className); - } - return null; - } - if (!classLoadingChecker.isFirstLoad(className)) { - if (isDebug) { - logger.debug("skip already loaded class:{}", className); - } - return null; - } - - Class c = null; - try { - c = classLoader.loadClass(className); - if (isDebug) { - logger.debug("loadClass:{}", className); - } - } catch (ClassNotFoundException ex) { - if (isDebug) { - logger.debug("ClassNotFound {}", ex.getMessage()); - } - } - if (c != null) { - return c; - } - - final CtClass ct = pool.getOrNull(className); - if (ct == null) { - throw new NotFoundException(className); - } - - - final CtClass superClass = ct.getSuperclass(); - if (superClass != null) { - if ("java.lang.Object".equals(superClass.getName())) { - return null; - } - injectToPlainClassLoader(pool, classLoader, superClass.getName(), classLoadingChecker); - } - - final CtClass[] interfaces = ct.getInterfaces(); - for (CtClass ctInterface : interfaces) { - injectToPlainClassLoader(pool, classLoader, ctInterface.getName(), classLoadingChecker); - } - @SuppressWarnings("unchecked") - final Collection referenceClassList = ct.getRefClasses(); - if (isDebug) { - logger.debug("target:{} referenceClassList:{}", className, referenceClassList); - } - for (String referenceClass : referenceClassList) { - try { - injectToPlainClassLoader(pool, classLoader, referenceClass, classLoadingChecker); - } catch (NotFoundException e) { - logger.warn("Skip a referenced class because of NotFoundException : {}", e.getMessage(), e); - } - } - if (logger.isInfoEnabled()) { - logger.info("defineClass pluginClass:{} cl:{}", className, classLoader); - } - final byte[] bytes = ct.toBytecode(); - return (Class)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length); - } - } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/PlainClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/PlainClassLoaderHandler.java new file mode 100644 index 000000000..0596326dd --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/PlainClassLoaderHandler.java @@ -0,0 +1,186 @@ +/* + * * + * * 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. + * + */ + +/* + * * + * * 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.profiler.instrument; + +import com.navercorp.pinpoint.exception.PinpointException; +import com.navercorp.pinpoint.profiler.plugin.ClassLoadingChecker; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.LoaderClassPath; +import javassist.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import java.util.Collection; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PlainClassLoaderHandler implements ClassInjector { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private static final Method DEFINE_CLASS; + + static { + try { + DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); + DEFINE_CLASS.setAccessible(true); + } catch (Exception e) { + throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e); + } + } + + private final PluginConfig pluginConfig; + + + public PlainClassLoaderHandler(PluginConfig pluginConfig) { + if (pluginConfig == null) { + throw new NullPointerException("pluginConfig must not be null"); + } + this.pluginConfig = pluginConfig; + } + + @Override + @SuppressWarnings("unchecked") + public Class injectClass(ClassLoader classLoader, String className) { + try { + return (Class)injectClass0(classLoader, className); + } catch (Exception e) { + logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); + throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e); + } + } + + + private Class injectClass0(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException { + if (isDebug) { + logger.debug("injectClass0 className:{} cl:{}", className, classLoader); + } + logger.info("bootstrapCoreJarPath:{}", pluginConfig.getBootstrapCoreJarPath()); + + final ClassPool pool = createClassPool(classLoader); + + // TODO ClassLoader + ClassName key? + // TODO concurrent class loading + final ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker(); + return injectClass0(pool, classLoader, className, classLoadingChecker); + } + + private ClassPool createClassPool(ClassLoader classLoader) throws NotFoundException { + final ClassPool pool = new ClassPool(); + final String bootstrapCoreJarPath = pluginConfig.getBootstrapCoreJarPath(); + pool.appendClassPath(bootstrapCoreJarPath); + + final LoaderClassPath loaderClassPath = new LoaderClassPath(classLoader); + pool.appendClassPath(loaderClassPath); + + final String pluginJarFileName = pluginConfig.getPluginJarFile().getName(); + pool.appendClassPath(pluginJarFileName); + return pool; + } + + private Class injectClass0(ClassPool pool, ClassLoader classLoader, String className, ClassLoadingChecker classLoadingChecker) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { + if (!pluginConfig.getPluginPackageFilter().accept(className)) { + if (isDebug) { + logger.debug("PluginFilter skip class:{}", className); + } + return null; + } + if (!classLoadingChecker.isFirstLoad(className)) { + if (isDebug) { + logger.debug("skip already loaded class:{}", className); + } + return null; + } + + Class c = null; + try { + c = classLoader.loadClass(className); + if (isDebug) { + logger.debug("loadClass:{}", className); + } + } catch (ClassNotFoundException ex) { + if (isDebug) { + logger.debug("ClassNotFound {}", ex.getMessage()); + } + } + if (c != null) { + return c; + } + + final CtClass ct = pool.getOrNull(className); + if (ct == null) { + throw new NotFoundException(className); + } + + + final CtClass superClass = ct.getSuperclass(); + if (superClass != null) { + if ("java.lang.Object".equals(superClass.getName())) { + return null; + } + injectClass0(pool, classLoader, superClass.getName(), classLoadingChecker); + } + + final CtClass[] interfaces = ct.getInterfaces(); + for (CtClass ctInterface : interfaces) { + injectClass0(pool, classLoader, ctInterface.getName(), classLoadingChecker); + } + @SuppressWarnings("unchecked") + final Collection referenceClassList = ct.getRefClasses(); + if (isDebug) { + logger.debug("target:{} referenceClassList:{}", className, referenceClassList); + } + for (String referenceClass : referenceClassList) { + try { + injectClass0(pool, classLoader, referenceClass, classLoadingChecker); + } catch (NotFoundException e) { + logger.warn("Skip a referenced class because of NotFoundException : {}", e.getMessage(), e); + } + } + if (logger.isInfoEnabled()) { + logger.info("defineClass pluginClass:{} cl:{}", className, classLoader); + } + final byte[] bytes = ct.toBytecode(); + return (Class)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/URLClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/URLClassLoaderHandler.java new file mode 100644 index 000000000..1e9498a7e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/URLClassLoaderHandler.java @@ -0,0 +1,122 @@ +/* + * * + * * 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. + * + */ + +/* + * * + * * 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.profiler.instrument; + +import com.navercorp.pinpoint.exception.PinpointException; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * @author Woonduk Kang(emeroad) + */ +public class URLClassLoaderHandler implements ClassInjector { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final Method ADD_URL; + + static { + try { + ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + ADD_URL.setAccessible(true); + } catch (Exception e) { + throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e); + } + } + + private final URL pluginURL; + private final String pluginURLString; + + public URLClassLoaderHandler(PluginConfig pluginConfig) { + if (pluginConfig == null) { + throw new NullPointerException("pluginConfig must not be null"); + } + this.pluginURL = pluginConfig.getPluginJar(); + this.pluginURLString = pluginURL.toExternalForm(); + } + + @Override + @SuppressWarnings("unchecked") + public Class injectClass(ClassLoader classLoader, String className) { + try { + if (classLoader instanceof URLClassLoader) { + final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; + return (Class)injectClass0(urlClassLoader, className); + } + } catch (Exception e) { + logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); + throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e); + } + throw new PinpointException("invalid ClassLoader"); + } + + + + private Class injectClass0(URLClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + final URL[] urls = classLoader.getURLs(); + if (urls != null) { + + final boolean hasPluginJar = hasPluginJar(urls); + + if (!hasPluginJar) { + logger.debug("add Jar:{}", pluginURLString); + ADD_URL.invoke(classLoader, pluginURL); + } + } + + return classLoader.loadClass(className); + } + + private boolean hasPluginJar(URL[] urls) { + for (URL url : urls) { + // if (url.equals(pluginJarURL)) { fix very slow + // http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html + final String externalForm = url.toExternalForm(); + if (pluginURLString.equals(externalForm)) { + + return true; + } + } + return false; + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java new file mode 100644 index 000000000..801abc09b --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java @@ -0,0 +1,47 @@ +/* + * * + * * 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.profiler.plugin; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassNameFilterChain implements ClassNameFilter { + + private final List filterChain; + + public ClassNameFilterChain(List filterChain) { + if (filterChain == null) { + throw new NullPointerException("filterChain must not be null"); + } + this.filterChain = new ArrayList(filterChain); + } + + + @Override + public boolean accept(String className) { + for (ClassNameFilter classNameFilter : this.filterChain) { + if (!classNameFilter.accept(className)) { + return REJECT; + } + } + return ACCEPT; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilter.java new file mode 100644 index 000000000..5ce71bc9e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilter.java @@ -0,0 +1,74 @@ +/* + * * + * * 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.profiler.plugin; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PinpointProfilerPackageSkipFilter implements ClassNameFilter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final List packageList; + + public PinpointProfilerPackageSkipFilter() { + this(getPinpointPackageList()); + } + + public PinpointProfilerPackageSkipFilter(List packageList) { + if (packageList == null) { + throw new NullPointerException("packageList must not be null"); + } + this.packageList = new ArrayList(packageList); + } + + + + @Override + public boolean accept(String className) { + if (className == null) { + throw new NullPointerException("className must not be null"); + } + + for (String packageName : packageList) { + if (className.startsWith(packageName)) { + if (logger.isDebugEnabled()) { + logger.info("skip ProfilerPackage:{} Class:{}", packageName, className); + } + return REJECT; + } + } + return ACCEPT; + } + + private static List getPinpointPackageList() { + List pinpointPackageList = new ArrayList(); + pinpointPackageList.add("com.navercorp.pinpoint.bootstrap"); + pinpointPackageList.add("com.navercorp.pinpoint.profiler"); + pinpointPackageList.add("com.navercorp.pinpoint.common"); + pinpointPackageList.add("com.navercorp.pinpoint.exception"); + // TODO move test package + pinpointPackageList.add("com.navercorp.pinpoint.test"); + return pinpointPackageList; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java index 3ea006ffe..7543b58d1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java @@ -19,7 +19,6 @@ package com.navercorp.pinpoint.profiler.plugin; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClassPool; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; -import com.navercorp.pinpoint.bootstrap.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,9 +30,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.List; -import java.util.jar.Attributes; import java.util.jar.JarFile; -import java.util.jar.Manifest; /** * @author Woonduk Kang(emeroad) @@ -50,15 +47,14 @@ public class PluginConfig { private String pluginJarURLExternalForm; private final ProfilerPlugin plugin; - private final Manifest manifest; private final Instrumentation instrumentation; private final InstrumentClassPool classPool; private final String bootstrapCoreJarPath; - private final ClassNameFilter pluginPackageFilter; - private final ClassNameFilter profilerPackageFilter; - public PluginConfig(URL pluginJar, ProfilerPlugin plugin, Instrumentation instrumentation, InstrumentClassPool classPool, String bootstrapCoreJarPath) { + private final ClassNameFilter pluginPackageFilter; + + public PluginConfig(URL pluginJar, ProfilerPlugin plugin, Instrumentation instrumentation, InstrumentClassPool classPool, String bootstrapCoreJarPath, ClassNameFilter pluginPackageFilter) { if (pluginJar == null) { throw new NullPointerException("pluginJar must not be null"); } @@ -68,37 +64,16 @@ public class PluginConfig { this.pluginJar = pluginJar; this.pluginJarFile = createJarFile(pluginJar); this.plugin = plugin; - this.manifest = this.getManifest(); this.instrumentation = instrumentation; this.classPool = classPool; this.bootstrapCoreJarPath = bootstrapCoreJarPath; - final List pluginPackageList = getPluginPackage(manifest); - if (logger.isInfoEnabled()) { - logger.info("{} Plugin Package:{}", plugin.getClass(), pluginPackageList); - } - this.pluginPackageFilter = new PluginPackageFilter(pluginPackageList); - this.profilerPackageFilter = new PinpointProfilerPackageFilter(); + this.pluginPackageFilter = pluginPackageFilter; } - private Manifest getManifest() { - try { - return pluginJarFile.getManifest(); - } catch (IOException e) { - // return empty - return new Manifest(); - } - } - public List getPluginPackage(Manifest manifest) { - final Attributes attributes = manifest.getMainAttributes(); - final String pluginPackage = attributes.getValue(PINPOINT_PLUGIN_PACKAGE); - if (pluginPackage == null) { - return DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME; - } - return StringUtils.splitAndTrim(pluginPackage, ","); - } + public ProfilerPlugin getPlugin() { return plugin; @@ -146,7 +121,5 @@ public class PluginConfig { return pluginPackageFilter; } - public ClassNameFilter getProfilerPackageFilter() { - return profilerPackageFilter; - } -} + +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java index df996756d..7a4d8b8e3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java @@ -14,14 +14,23 @@ */ package com.navercorp.pinpoint.profiler.plugin; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; import com.navercorp.pinpoint.bootstrap.instrument.GuardInstrumentContext; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +48,8 @@ public class ProfilerPluginLoader { private final Logger logger = LoggerFactory.getLogger(getClass()); private final DefaultAgent agent; + private final ClassNameFilter profilerPackageFilter = new PinpointProfilerPackageSkipFilter(); + public ProfilerPluginLoader(DefaultAgent agent) { if (agent == null) { throw new NullPointerException("agent must not be null"); @@ -51,31 +62,87 @@ public class ProfilerPluginLoader { List disabled = agent.getProfilerConfig().getDisabledPlugins(); for (URL jar : pluginJars) { - List plugins = PluginLoader.load(ProfilerPlugin.class, new URL[] { jar }); - + + final JarFile pluginJarFile = createJarFile(jar); + final List pluginPackageList = getPluginPackage(pluginJarFile); + + final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList); + + final List plugins = PluginLoader.load(ProfilerPlugin.class, new URL[] { jar }); + for (ProfilerPlugin plugin : plugins) { if (disabled.contains(plugin.getClass().getName())) { logger.info("Skip disabled plugin: {}", plugin.getClass().getName()); continue; } + if (logger.isInfoEnabled()) { + logger.info("{} Plugin {}:{}", plugin.getClass(), PluginConfig.PINPOINT_PLUGIN_PACKAGE, pluginPackageList); + } - logger.info("Loading plugin: {}", plugin.getClass().getName()); + logger.info("Loading plugin:{} pluginPackage:{}", plugin.getClass().getName(), plugin); - PluginConfig pluginConfig = new PluginConfig(jar, plugin, agent.getInstrumentation(), agent.getClassPool(), agent.getBootstrapCoreJar()); + PluginConfig pluginConfig = new PluginConfig(jar, plugin, agent.getInstrumentation(), agent.getClassPool(), agent.getBootstrapCoreJar(), pluginFilterChain); final DefaultProfilerPluginContext context = setupPlugin(pluginConfig); pluginContexts.add(context); } } - + return pluginContexts; } + private ClassNameFilter createPluginFilterChain(List packageList) { + + final ClassNameFilter pluginPackageFilter = new PluginPackageFilter(packageList); + + final List chain = Arrays.asList(profilerPackageFilter, pluginPackageFilter); + + final ClassNameFilter filterChain = new ClassNameFilterChain(chain); + + return filterChain; + } + + private JarFile createJarFile(URL pluginJar) { + try { + final URI uri = pluginJar.toURI(); + return new JarFile(new File(uri)); + } catch (URISyntaxException e) { + throw new RuntimeException("URISyntax error. " + e.getCause(), e); + } catch (IOException e) { + throw new RuntimeException("IO error. " + e.getCause(), e); + } + } + private Manifest getManifest(JarFile pluginJarFile) { + try { + return pluginJarFile.getManifest(); + } catch (IOException ex) { + logger.info("{} IoError :{}", pluginJarFile.getName(), ex.getMessage(), ex); + return null; + } + } + + public List getPluginPackage(JarFile pluginJarFile) { + + final Manifest manifest = getManifest(pluginJarFile); + if (manifest == null) { + return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME; + } + + final Attributes attributes = manifest.getMainAttributes(); + final String pluginPackage = attributes.getValue(PluginConfig.PINPOINT_PLUGIN_PACKAGE); + if (pluginPackage == null) { + return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME; + } + return StringUtils.splitAndTrim(pluginPackage, ","); + } + + private GuardInstrumentContext preparePlugin(ProfilerPlugin plugin, InstrumentContext context) { + final GuardInstrumentContext guardInstrumentContext = new GuardInstrumentContext(context); if (plugin instanceof TransformTemplateAware) { if (logger.isDebugEnabled()) { - logger.debug("setTransformTemplate {}", plugin.getClass().getName()); + logger.debug("{}.setTransformTemplate", plugin.getClass().getName()); } final TransformTemplate transformTemplate = new TransformTemplate(guardInstrumentContext); ((TransformTemplateAware) plugin).setTransformTemplate(transformTemplate); @@ -92,6 +159,9 @@ public class ProfilerPluginLoader { try { // WARN external plugin api final ProfilerPlugin plugin = pluginConfig.getPlugin(); + if (logger.isInfoEnabled()) { + logger.info("{} Plugin setup", plugin.getClass().getName()); + } plugin.setup(guardPluginContext); } finally { guardPluginContext.close(); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjectorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjectorTest.java new file mode 100644 index 000000000..b7147acbc --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JarProfilerPluginClassInjectorTest.java @@ -0,0 +1,129 @@ +/* + * * + * * 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. + * + */ + +/* + * * + * * 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.profiler.instrument; + +import com.navercorp.pinpoint.bootstrap.LibClass; +import com.navercorp.pinpoint.bootstrap.PinpointURLClassLoader; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClassPool; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import com.navercorp.pinpoint.profiler.plugin.PluginPackageFilter; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ReflectionUtils; + +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.security.CodeSource; +import java.util.Arrays; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarProfilerPluginClassInjectorTest { + + public static final String CONTEXT_TYPE_MATCH_CLASS_LOADER = "org.springframework.context.support.ContextTypeMatchClassLoader"; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void testInjectClass() throws Exception { + final URL sampleJar = getSampleJar(Logger.class); + + final ClassLoader contextTypeMatchClassLoader = createContextTypeMatchClassLoader(new URL[]{sampleJar}); + + InstrumentClassPool pool = Mockito.mock(InstrumentClassPool.class); + final Instrumentation instrumentation = Mockito.mock(Instrumentation.class); + final ProfilerPlugin profilerPlugin = Mockito.mock(ProfilerPlugin.class); + + +// final PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList("test")); + final String packageName = logger.getClass().getPackage().getName(); + final PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList(packageName)); + PluginConfig pluginConfig = new PluginConfig(sampleJar, profilerPlugin, instrumentation, pool, sampleJar.getPath(), filter); + + PlainClassLoaderHandler injector = new PlainClassLoaderHandler(pluginConfig); + final Class loggerClass = injector.injectClass(contextTypeMatchClassLoader, logger.getClass().getName()); + + logger.debug("ClassLoader{}", loggerClass.getClassLoader()); + Assert.assertEquals("check className", loggerClass.getName(), "org.slf4j.impl.Log4jLoggerAdapter"); + Assert.assertEquals("check ClassLoader", loggerClass.getClassLoader().getClass().getName(), CONTEXT_TYPE_MATCH_CLASS_LOADER); + + } + + private ClassLoader createContextTypeMatchClassLoader(URL[] urlArray) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException { + final ClassLoader classLoader = this.getClass().getClassLoader(); + final Class aClass = (Class) classLoader.loadClass(CONTEXT_TYPE_MATCH_CLASS_LOADER); + final Constructor constructor = aClass.getConstructor(ClassLoader.class); + ReflectionUtils.makeAccessible(constructor); + + final LibClass libClassFilter = new LibClass() { + @Override + public boolean onLoadClass(String clazzName) { + if (clazzName.startsWith("org.slf4j")) { + logger.debug("Loading {}", clazzName); + return ON_LOAD_CLASS; + } + return DELEGATE_PARENT; + } + }; + PinpointURLClassLoader testClassLoader = new PinpointURLClassLoader(urlArray, ClassLoader.getSystemClassLoader(), libClassFilter); + + final ClassLoader contextTypeMatchClassLoader = constructor.newInstance(testClassLoader); + + logger.debug("cl:{}",contextTypeMatchClassLoader); + +// final Method excludePackage = aClass.getMethod("excludePackage", String.class); +// ReflectionUtils.invokeMethod(excludePackage, contextTypeMatchClassLoader, "org.slf4j"); + + + return contextTypeMatchClassLoader; + } + + + private URL getSampleJar(Class clazz) { + final CodeSource codeSource = clazz.getProtectionDomain().getCodeSource(); + final URL location = codeSource.getLocation(); + + logger.debug("url:{}", location); + + return location; + } + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChainTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChainTest.java new file mode 100644 index 000000000..12920ad04 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChainTest.java @@ -0,0 +1,43 @@ +/* + * * + * * 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.profiler.plugin; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassNameFilterChainTest { + + @Test + public void testAccept() throws Exception { + PluginPackageFilter include = new PluginPackageFilter(Arrays.asList("com.include")); + PinpointProfilerPackageSkipFilter exclude = new PinpointProfilerPackageSkipFilter(Arrays.asList("com.exclude")); + + ClassNameFilterChain chain = new ClassNameFilterChain(Arrays.asList(include, exclude)); + + + Assert.assertTrue(chain.accept("com.include")); + Assert.assertFalse(chain.accept("com.exclude")); + + Assert.assertFalse(chain.accept("unknown")); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilterTest.java new file mode 100644 index 000000000..3207cb84a --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PinpointProfilerPackageSkipFilterTest.java @@ -0,0 +1,37 @@ +/* + * * + * * 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.profiler.plugin; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PinpointProfilerPackageSkipFilterTest { + + @Test + public void testAccept() throws Exception { + + PinpointProfilerPackageSkipFilter filter = new PinpointProfilerPackageSkipFilter(); + Assert.assertFalse("skip", filter.accept("com.navercorp.pinpoint.bootstrap.test.class")); + + Assert.assertTrue("include", filter.accept("test")); + + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PluginPackageFilterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PluginPackageFilterTest.java new file mode 100644 index 000000000..7d5fb6da8 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/PluginPackageFilterTest.java @@ -0,0 +1,40 @@ +/* + * * + * * 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.profiler.plugin; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PluginPackageFilterTest { + + @Test + public void testAccept() throws Exception { + PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList("com.plugin")); + + Assert.assertTrue(filter.accept("com.plugin.test.module")); + + Assert.assertFalse(filter.accept("test")); + } +} \ No newline at end of file