AbstractClassEnhancePluginDefine.java 3.8 KB
Newer Older
1
package org.skywalking.apm.agent.core.plugin;
2

A
ascrutae 已提交
3
import net.bytebuddy.dynamic.DynamicType;
wu-sheng's avatar
wu-sheng 已提交
4
import net.bytebuddy.pool.TypePool;
A
ascrutae 已提交
5
import net.bytebuddy.pool.TypePool.Resolution;
6 7
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
import org.skywalking.apm.util.StringUtil;
P
pengys5 已提交
8 9
import org.skywalking.apm.logging.ILog;
import org.skywalking.apm.logging.LogManager;
10

11 12 13 14
/**
 * Basic abstract class of all sky-walking auto-instrumentation plugins.
 * <p>
 * It provides the outline of enhancing the target class.
15
 * If you want to know more about enhancing, you should go to see {@link ClassEnhancePluginDefine}
16 17
 */
public abstract class AbstractClassEnhancePluginDefine {
18
    private static final ILog logger = LogManager.getLogger(AbstractClassEnhancePluginDefine.class);
19

wu-sheng's avatar
wu-sheng 已提交
20 21
    private TypePool classTypePool;

22 23 24 25
    /**
     * Main entrance of enhancing the class.
     *
     * @param transformClassName target class.
P
pengys5 已提交
26
     * @param builder            byte-buddy's builder to manipulate target class's bytecode.
27
     * @return the new builder, or <code>null</code> if not be enhanced.
28 29
     * @throws PluginException, when set builder failure.
     */
30
    public DynamicType.Builder<?> define(String transformClassName,
P
pengys5 已提交
31
                                         DynamicType.Builder<?> builder) throws PluginException {
32 33
        String interceptorDefineClassName = this.getClass().getName();

34
        if (StringUtil.isEmpty(transformClassName)) {
35
            logger.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName);
36
            return null;
37 38
        }

39
        logger.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);
40

41 42 43 44
        /**
         * find witness classes for enhance class
         */
        String[] witnessClasses = witnessClasses();
45
        if (witnessClasses != null) {
A
ascrutae 已提交
46
            for (String witnessClass : witnessClasses) {
wu-sheng's avatar
wu-sheng 已提交
47
                Resolution witnessClassResolution = classTypePool.describe(witnessClass);
A
ascrutae 已提交
48
                if (!witnessClassResolution.isResolved()) {
49
                    logger.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName,
50
                        witnessClass);
51
                    return null;
52 53 54 55
                }
            }
        }

A
ascrutae 已提交
56 57 58
        /**
         * find origin class source code for interceptor
         */
59
        DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder);
60

61
        logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
A
ascrutae 已提交
62

63
        return newClassBuilder;
64 65
    }

66
    protected abstract DynamicType.Builder<?> enhance(String enhanceOriginClassName,
P
pengys5 已提交
67
                                                      DynamicType.Builder<?> newClassBuilder) throws PluginException;
68 69

    /**
70
     * Define the classname of target class.
71
     *
72
     * @return class full name.
73 74
     */
    protected abstract String enhanceClassName();
75

76
    /**
77 78 79 80 81 82
     * 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.
83 84 85
     *
     * @return
     */
86 87
    protected String[] witnessClasses() {
        return new String[] {};
88
    }
wu-sheng's avatar
wu-sheng 已提交
89 90 91 92

    public void setClassTypePool(TypePool classTypePool) {
        this.classTypePool = classTypePool;
    }
93
}