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

io.opentelemetry.javaagent.bootstrap.HelperResources Maven / Gradle / Ivy

The newest version!
/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package io.opentelemetry.javaagent.bootstrap;

import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;

import io.opentelemetry.instrumentation.api.internal.cache.Cache;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nullable;

/**
 * A holder of resources needed by instrumentation. We store them in the bootstrap class loader so
 * instrumentation can store from the agent class loader and apps can retrieve from the app class
 * loader.
 */
public final class HelperResources {

  private static final Cache>> RESOURCES = Cache.weak();
  private static final Map> ALL_CLASSLOADERS_RESOURCES =
      new ConcurrentHashMap<>();

  /**
   * Registers the {@code urls} to be available to instrumentation at {@code path}, when given
   * {@code classLoader} attempts to load that resource.
   */
  public static void register(ClassLoader classLoader, String path, List urls) {
    RESOURCES
        .computeIfAbsent(classLoader, unused -> new ConcurrentHashMap<>())
        .compute(path, (k, v) -> append(v, urls));
  }

  /** Registers the {@code urls} to be available to instrumentation at {@code path}. */
  public static void registerForAllClassLoaders(String path, List urls) {
    ALL_CLASSLOADERS_RESOURCES.compute(path, (k, v) -> append(v, urls));
  }

  private static List append(@Nullable List resources, List toAdd) {
    List newResources = resources == null ? new ArrayList<>() : new ArrayList<>(resources);
    for (URL newResource : toAdd) {
      // make sure to de-dupe resources - each extension class loader has the agent class loader as
      // its parent, and the MultipleParentClassLoader (that every individual extension CL gets put
      // into) concatenates all found resources on getResources(); this means that if you ask for a
      // built-in agent resource, each extension CL will also return URL pointing to it, thus the
      // final collection will have (no of extension CLs) + 1 duplicates of the same URL
      if (!containsSameFile(newResources, newResource)) {
        newResources.add(newResource);
      }
    }
    return unmodifiableList(newResources);
  }

  private static boolean containsSameFile(List haystack, URL needle) {
    for (URL r : haystack) {
      if (r.sameFile(needle)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Returns a {@link URL} that can be used to retrieve the content of the resource at {@code path},
   * or {@code null} if no resource could be found at {@code path}.
   */
  public static URL loadOne(ClassLoader classLoader, String path) {
    List resources = loadAll(classLoader, path);
    return resources.isEmpty() ? null : resources.get(0);
  }

  /**
   * Returns all {@link URL}s that can be used to retrieve the content of the resource at {@code
   * path}.
   */
  public static List loadAll(ClassLoader classLoader, String path) {
    Map> map = RESOURCES.get(classLoader);
    List resources = null;
    if (map != null) {
      resources = map.get(path);
    }
    if (resources == null) {
      resources = ALL_CLASSLOADERS_RESOURCES.get(path);
    }
    return resources == null ? emptyList() : resources;
  }

  private HelperResources() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy