package org.skywalking.apm.agent.core.plugin; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.pool.TypePool; import net.bytebuddy.pool.TypePool.Resolution; import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; import org.skywalking.apm.util.StringUtil; import org.skywalking.apm.logging.ILog; import org.skywalking.apm.logging.LogManager; /** * Basic abstract class of all sky-walking auto-instrumentation plugins. * <p> * It provides the outline of enhancing the target class. * If you want to know more about enhancing, you should go to see {@link ClassEnhancePluginDefine} */ public abstract class AbstractClassEnhancePluginDefine { private static final ILog logger = LogManager.getLogger(AbstractClassEnhancePluginDefine.class); private TypePool classTypePool; /** * Main entrance of enhancing the class. * * @param transformClassName target class. * @param builder byte-buddy's builder to manipulate target class's bytecode. * @return the new builder, or <code>null</code> if not be enhanced. * @throws PluginException, when set builder failure. */ public DynamicType.Builder<?> define(String transformClassName, DynamicType.Builder<?> builder) throws PluginException { String interceptorDefineClassName = this.getClass().getName(); if (StringUtil.isEmpty(transformClassName)) { logger.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName); return null; } logger.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName); /** * find witness classes for enhance class */ String[] witnessClasses = witnessClasses(); if (witnessClasses != null) { for (String witnessClass : witnessClasses) { Resolution witnessClassResolution = classTypePool.describe(witnessClass); if (!witnessClassResolution.isResolved()) { logger.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName, witnessClass); return null; } } } /** * find origin class source code for interceptor */ DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder); logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName); return newClassBuilder; } protected abstract DynamicType.Builder<?> enhance(String enhanceOriginClassName, DynamicType.Builder<?> newClassBuilder) throws PluginException; /** * Define the classname of target class. * * @return class full name. */ protected abstract String enhanceClassName(); /** * Witness classname list. Why need witness classname? Let's see like this: A library existed two released versions * (like 1.0, 2.0), which include the same target classes, but because of version iterator, they may have the same * name, but different methods, or different method arguments list. So, if I want to target the particular version * (let's say 1.0 for example), version number is obvious not an option, this is the moment you need "Witness * classes". You can add any classes only in this particular release version ( something like class * com.company.1.x.A, only in 1.0 ), and you can achieve the goal. * * @return */ protected String[] witnessClasses() { return new String[] {}; } public void setClassTypePool(TypePool classTypePool) { this.classTypePool = classTypePool; } }