All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.elastic.apm.agent.sdk.internal.PluginClassLoaderRootPackageCustomizer Maven / Gradle / Ivy

There is a newer version: 1.50.0
Show newest version
/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. 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.
 */
package co.elastic.apm.agent.sdk.internal;

import java.lang.instrument.Instrumentation;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
 * This class must be provided at most once per {@linkplain #getPluginPackage() plugin package}.
 */
public abstract class PluginClassLoaderRootPackageCustomizer {

    /**
     * The root package name prefix that all embedded plugins classes must start with
     */
    private static final String EMBEDDED_PLUGINS_PACKAGE_PREFIX = "co.elastic.apm.agent.";

    private final String pluginPackage;

    public PluginClassLoaderRootPackageCustomizer() {
        String className = getClass().getName();
        pluginPackage = getPluginPackageFromClassName(className);
    }

    public static String getPluginPackageFromClassName(String className) {
        if (!className.startsWith(EMBEDDED_PLUGINS_PACKAGE_PREFIX)) {
            throw new IllegalArgumentException("invalid instrumentation class location : " + className);
        }
        return className.substring(0, className.indexOf('.', EMBEDDED_PLUGINS_PACKAGE_PREFIX.length()));
    }

    public final String getPluginPackage() {
        return pluginPackage;
    }

    /**
     * All classes in the provided packages except for the ones annotated with {@link co.elastic.apm.agent.sdk.state.GlobalState}
     * and classes extending {@code org.stagemonitor.configuration.ConfigurationOptionProvider}
     * will be loaded from a dedicated plugin class loader that has access to both the instrumented classes and the agent classes.
     * If the {@linkplain #getPluginPackage() plugin package} should be part of the root packages, implementations need to explicitly add it.
     */
    public abstract Collection pluginClassLoaderRootPackages();

    /**
     * Starting with Java 9, Java added a module system which allows restricting access to code within modules.
     * From Java 9 to 16, illegal access print a warning on a console.
     * Starting with Java 17, Illegal access cause {@link  IllegalAccessException}s.
     * 

* Instrumentation plugins are loaded in an isolated classloader and therefore in an unnamed module. * This module by default cannot access anything "private" within other modules, including * the module containing the instrumented class. If such access is required for the plugin, * access can be granted using this method. Before anything from the plugin is invoked, * {@link Instrumentation#redefineModule(Module, Set, Map, Map, Set, Map) will be used to give the classloader * full access ("open") to the target module.} *

*

* Each entry within the result map corresponds to a module which needs to be made accessible. * Each module is looked up based on a "witness" class which resides within the respective module. * Therefore, the keys of the return value from this map are the fully qualified names of these witness classes. * The values of the map is a set of package names to open for the instrumentation plugin (like the * packages passed to the --add-opens command line argument). *

* IMPORTANT: The "witness" classes are looked up when an advice from the plugin is invoked for the first time. * It is best to provide classes which are known to be already loaded at that point in time in order * to not mess with class initialization order. For example, the instrumented class which invoked the * advice would be a safe choice. * * @return the map of "witness" FQNs to a collection of package names to open */ public Map> requiredModuleOpens() { return Collections.emptyMap(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy