// 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);
//         }
//     }
// }


import io.promagent.agent.ClassLoaderCache;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
import java.util.List;
import static net.bytebuddy.asm.Advice.*;
// 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;




public class PromagentAdvice {

    // TODO:
    // Should we move this class into it's own maven module
    // to make clear that it cannot reference other classes from promagent-internal?

    @OnMethodEnter
    @SuppressWarnings("unchecked")
    public static List<Object> before(
            @This(optional = true) Object that,
            @Origin Method method,
            @AllArguments Object[] args
    ) {
        // that is null when instrumenting static methods.
        Class<?> clazz = that != null ? that.getClass() : method.getDeclaringClass();
        try {
            // The following code is equivalent to:
            //     return Delegator.before(that, method, args);
            // However, the Delegator class will not be available in the context of the instrumented method,
            // so we must use our agent class loader to load the Delegator class and do the call via reflection.
// 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-internal/src/main/java/io/promagent/internal/PromagentAdvice.java
import io.promagent.agent.ClassLoaderCache;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
import java.util.List;
import static net.bytebuddy.asm.Advice.*;

// 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;




public class PromagentAdvice {

    // TODO:
    // Should we move this class into it's own maven module
    // to make clear that it cannot reference other classes from promagent-internal?

    @OnMethodEnter
    @SuppressWarnings("unchecked")
    public static List<Object> before(
            @This(optional = true) Object that,
            @Origin Method method,
            @AllArguments Object[] args
    ) {
        // that is null when instrumenting static methods.
        Class<?> clazz = that != null ? that.getClass() : method.getDeclaringClass();
        try {
            // The following code is equivalent to:
            //     return Delegator.before(that, method, args);
            // However, the Delegator class will not be available in the context of the instrumented method,
            // so we must use our agent class loader to load the Delegator class and do the call via reflection.
            Class<?> delegator = ClassLoaderCache.getInstance().currentClassLoader().loadClass("io.promagent.internal.Delegator");