/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. * */
/** * 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} */ publicabstractclassAbstractClassEnhancePluginDefine { privatestaticfinalILogLOGGER= LogManager.getLogger(AbstractClassEnhancePluginDefine.class);
/** * plugin name defined in skywalking-plugin.def */ private String pluginName; /** * New field name. */ publicstaticfinalStringCONTEXT_ATTR_NAME="_$EnhancedClassField_ws";
/** * Main entrance of enhancing the class. * * @param typeDescription target class description. * @param builder byte-buddy's builder to manipulate target class's bytecode. * @param classLoader load the given transformClass * @return the new builder, or <code>null</code> if not be enhanced. * @throws PluginException when set builder failure. */ public DynamicType.Builder<?> define(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext context) throws PluginException { StringinterceptorDefineClassName=this.getClass().getName(); StringtransformClassName= typeDescription.getTypeName(); if (StringUtil.isEmpty(transformClassName)) { LOGGER.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName); returnnull; }
LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName); WitnessFinderfinder= WitnessFinder.INSTANCE; /** * find witness classes for enhance class */ String[] witnessClasses = witnessClasses(); if (witnessClasses != null) { for (String witnessClass : witnessClasses) { if (!finder.exist(witnessClass, classLoader)) { LOGGER.warn("enhance class {} by plugin {} is not activated. Witness class {} does not exist.", transformClassName, interceptorDefineClassName, witnessClass); returnnull; } } } List<WitnessMethod> witnessMethods = witnessMethods(); if (!CollectionUtil.isEmpty(witnessMethods)) { for (WitnessMethod witnessMethod : witnessMethods) { if (!finder.exist(witnessMethod, classLoader)) { LOGGER.warn("enhance class {} by plugin {} is not activated. Witness method {} does not exist.", transformClassName, interceptorDefineClassName, witnessMethod); returnnull; } } }
/** * find origin class source code for interceptor */ DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);
context.initializationStageCompleted(); LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder; }
/** * Begin to define how to enhance class. After invoke this method, only means definition is finished. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ protected DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException { newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);
/** * Enhance a class to intercept constructors and class instance methods. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ protectedabstract DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException;
/** * Enhance a class to intercept class static methods. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ protectedabstract DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException;
/** * Define the {@link ClassMatch} for filtering class. * * @return {@link ClassMatch} */ protectedabstract ClassMatch enhanceClass();
/** * 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. */ protected String[] witnessClasses() { returnnewString[] {}; }
/** * plugin name should be set after create PluginDefine instance * * @param pluginName key defined in skywalking-plugin.def */ protectedvoidsetPluginName(final String pluginName) { this.pluginName = pluginName; }
public String getPluginName() { return pluginName; } }