// Path: promagent-framework/promagent-agent/src/main/java/io/promagent/agent/ClassLoaderCache.java
// public class ClassLoaderCache {
// 
//     private static ClassLoaderCache instance;
// 
//     // TODO: The cache does not free class loaders when applications are undeployed. Maybe use WeakHashMap?
//     private final Map<ClassLoader, PerDeploymentClassLoader> cache = new HashMap<>();
//     private final URLClassLoader sharedClassLoader; // shared across multiple deployments
//     private final List<Path> perDeploymentJars; // one class loader for each deployment for these JARs
// 
//     private ClassLoaderCache(JarFiles jarFiles) {
//         sharedClassLoader = new URLClassLoader(pathsToURLs(jarFiles.getSharedJars()));
//         perDeploymentJars = jarFiles.getPerDeploymentJars();
//     }
// 
//     public static synchronized ClassLoaderCache getInstance() {
//         if (instance == null) {
//             instance = new ClassLoaderCache(JarFiles.extract());
//         }
//         return instance;
//     }
// 
//     public List<Path> getPerDeploymentJars() {
//         return perDeploymentJars;
//     }
// 
//     public synchronized ClassLoader currentClassLoader() {
//         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
//         if (! cache.containsKey(contextClassLoader)) {
//             cache.put(contextClassLoader, new PerDeploymentClassLoader(pathsToURLs(perDeploymentJars), sharedClassLoader, contextClassLoader));
//         }
//         return cache.get(contextClassLoader);
//     }
// 
//     private static URL[] pathsToURLs(List<Path> paths) {
//         try {
//             URL[] result = new URL[paths.size()];
//             for (int i=0; i<paths.size(); i++) {
//                 result[i] = paths.get(i).toUri().toURL();
//             }
//             return result;
//         } catch (MalformedURLException e) {
//             throw new RuntimeException(e);
//         }
//     }
// }
// 
// Path: promagent-framework/promagent-api/src/main/java/io/promagent/hookcontext/MetricsStore.java
// public class MetricsStore {
// 
//     private final CollectorRegistry registry;
//     private final ConcurrentMap<String, Collector> metrics = new ConcurrentHashMap<>();
// 
//     public MetricsStore(CollectorRegistry registry) {
//         this.registry = registry;
//     }
// 
//     /**
//      * See {@link MetricsStore} and {@link MetricDef#MetricDef(String, BiFunction)}.
//      */
//     @SuppressWarnings("unchecked")
//     public <T extends Collector> T createOrGet(MetricDef<T> metricDef) {
//         return (T) metrics.computeIfAbsent(metricDef.getMetricName(), s -> metricDef.getProducer().apply(metricDef.getMetricName(), registry));
//     }
// }


import io.promagent.agent.ClassLoaderCache;
import io.promagent.annotations.After;
import io.promagent.annotations.Before;
import io.promagent.annotations.Returned;
import io.promagent.annotations.Thrown;
import io.promagent.hookcontext.MetricsStore;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// Copyright 2017 The Promagent Authors
//
// Licensed 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 io.promagent.internal;



/**
 * Delegator is called from the Byte Buddy Advice, and calls the Hook's @Before and @After methods.
 * <p>
 * TODO: This is called often, should be performance optimized, e.g. caching hook method handles, etc.
 */
public class Delegator {

    private static Delegator instance; // not thread-safe, but it is set only once in the agent's premain method.

    private final SortedSet<HookMetadata> hookMetadata;
    private final MetricsStore metricsStore;
// Path: promagent-framework/promagent-agent/src/main/java/io/promagent/agent/ClassLoaderCache.java
// public class ClassLoaderCache {
// 
//     private static ClassLoaderCache instance;
// 
//     // TODO: The cache does not free class loaders when applications are undeployed. Maybe use WeakHashMap?
//     private final Map<ClassLoader, PerDeploymentClassLoader> cache = new HashMap<>();
//     private final URLClassLoader sharedClassLoader; // shared across multiple deployments
//     private final List<Path> perDeploymentJars; // one class loader for each deployment for these JARs
// 
//     private ClassLoaderCache(JarFiles jarFiles) {
//         sharedClassLoader = new URLClassLoader(pathsToURLs(jarFiles.getSharedJars()));
//         perDeploymentJars = jarFiles.getPerDeploymentJars();
//     }
// 
//     public static synchronized ClassLoaderCache getInstance() {
//         if (instance == null) {
//             instance = new ClassLoaderCache(JarFiles.extract());
//         }
//         return instance;
//     }
// 
//     public List<Path> getPerDeploymentJars() {
//         return perDeploymentJars;
//     }
// 
//     public synchronized ClassLoader currentClassLoader() {
//         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
//         if (! cache.containsKey(contextClassLoader)) {
//             cache.put(contextClassLoader, new PerDeploymentClassLoader(pathsToURLs(perDeploymentJars), sharedClassLoader, contextClassLoader));
//         }
//         return cache.get(contextClassLoader);
//     }
// 
//     private static URL[] pathsToURLs(List<Path> paths) {
//         try {
//             URL[] result = new URL[paths.size()];
//             for (int i=0; i<paths.size(); i++) {
//                 result[i] = paths.get(i).toUri().toURL();
//             }
//             return result;
//         } catch (MalformedURLException e) {
//             throw new RuntimeException(e);
//         }
//     }
// }
// 
// Path: promagent-framework/promagent-api/src/main/java/io/promagent/hookcontext/MetricsStore.java
// public class MetricsStore {
// 
//     private final CollectorRegistry registry;
//     private final ConcurrentMap<String, Collector> metrics = new ConcurrentHashMap<>();
// 
//     public MetricsStore(CollectorRegistry registry) {
//         this.registry = registry;
//     }
// 
//     /**
//      * See {@link MetricsStore} and {@link MetricDef#MetricDef(String, BiFunction)}.
//      */
//     @SuppressWarnings("unchecked")
//     public <T extends Collector> T createOrGet(MetricDef<T> metricDef) {
//         return (T) metrics.computeIfAbsent(metricDef.getMetricName(), s -> metricDef.getProducer().apply(metricDef.getMetricName(), registry));
//     }
// }


// Path: promagent-framework/promagent-internal/src/main/java/io/promagent/internal/Delegator.java
import io.promagent.agent.ClassLoaderCache;
import io.promagent.annotations.After;
import io.promagent.annotations.Before;
import io.promagent.annotations.Returned;
import io.promagent.annotations.Thrown;
import io.promagent.hookcontext.MetricsStore;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// Copyright 2017 The Promagent Authors
//
// Licensed 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 io.promagent.internal;



/**
 * Delegator is called from the Byte Buddy Advice, and calls the Hook's @Before and @After methods.
 * <p>
 * TODO: This is called often, should be performance optimized, e.g. caching hook method handles, etc.
 */
public class Delegator {

    private static Delegator instance; // not thread-safe, but it is set only once in the agent's premain method.

    private final SortedSet<HookMetadata> hookMetadata;
    private final MetricsStore metricsStore;
    private final ClassLoaderCache classLoaderCache;