class ProxyPlugin {
    private static AgentLogger LOGGER = AgentLogger.getLogger(ProxyPlugin.class);
    static boolean isJava8OrNewer = WatcherFactory.JAVA_VERSION >= 18;

    /**
     * Flag to check reload status. In unit test we need to wait for reload
     * finish before the test can continue. Set flag to true in the test class
     * and wait until the flag is false again.
     */
    public static boolean reloadFlag = false;

    private static Set<String> proxyRedefiningMap = ConcurrentHashMap.newKeySet();

    @OnClassLoadEvent(classNameRegexp = "(jdk.proxy\\d+.\\$Proxy.*)|(com.sun.proxy.\\$Proxy.*)", events = LoadEvent.REDEFINE, skipSynthetic = false)
    public static void transformJavaProxy(final Class<?> classBeingRedefined, final ClassLoader classLoader) {<FILL_FUNCTION_BODY>}

    public static void removeProxyDefiningClassName(String className) {
        proxyRedefiningMap.remove(className);
    }

    @OnClassLoadEvent(classNameRegexp = ".*", events = LoadEvent.REDEFINE, skipSynthetic = false)
    public static byte[] transformCglibProxy(final Class<?> classBeingRedefined, final byte[] classfileBuffer,
            final ClassLoader loader, final ClassPool cp) throws Exception {

        GeneratorParams generatorParams = GeneratorParametersTransformer.getGeneratorParams(loader, classBeingRedefined.getName());

        if (generatorParams == null) {
            return classfileBuffer;
        }

        if (!ClassLoaderHelper.isClassLoderStarted(loader)) {
            return classfileBuffer;
        }

        loader.loadClass("java.beans.Introspector").getMethod("flushCaches").invoke(null);
        if (generatorParams.getParam().getClass().getName().endsWith(".Enhancer")) {
            try {
                return CglibEnhancerProxyTransformer.transform(classBeingRedefined, cp, classfileBuffer, loader, generatorParams);
            } catch (Exception e) {
                LOGGER.error("Error redifining Cglib Enhancer proxy {}", e, classBeingRedefined.getName());
            }
        }

        // Multistep transformation crashed jvm in java8 u05
        if (!isJava8OrNewer) {
            try {
                return CglibProxyTransformer.transform(classBeingRedefined, cp, classfileBuffer, generatorParams);
            }
            catch (Exception e) {
                LOGGER.error("Error redifining Cglib proxy {}", e, classBeingRedefined.getName());
            }
        }

        return classfileBuffer;
    }

    /**
     * Modifies Cglib bytecode generators to store the parameters for this plugin
     *
     * @throws Exception
     */
    @OnClassLoadEvent(classNameRegexp = ".*/cglib/.*", skipSynthetic = false)
    public static CtClass transformDefinitions(CtClass cc) throws Exception {
        try {
            return GeneratorParametersTransformer.transform(cc);
        } catch (Exception e) {
            LOGGER.error("Error modifying class for cglib proxy creation parameter recording", e);
        }
        return cc;
    }
}


    /*
     * Proxy can't be redefined directly in this method (and return new proxy class bytes), since the classLoader contains
     * OLD definition of proxie's interface. Therefore proxy is defined in deferred command (after some delay)
     * after proxied interface is redefined in DCEVM.
     */
        Object proxyCache = ReflectionHelper.getNoException(null, java.lang.reflect.Proxy.class, "proxyCache");

        if (proxyCache != null) {
            try {
                ReflectionHelper.invoke(proxyCache, proxyCache.getClass().getSuperclass(), "removeAll",
                        new Class[] { ClassLoader.class }, classLoader);
            } catch (IllegalArgumentException e) {
                LOGGER.error("Reflection proxy cache flush failed. {}", e.getMessage());
            }
        }

        if (!ClassLoaderHelper.isClassLoderStarted(classLoader)) {
            return;
        }

        final String className = classBeingRedefined.getName();

        if (proxyRedefiningMap.contains(className)) {
            proxyRedefiningMap.remove(className);
            return;
        }

        proxyRedefiningMap.add(className);

        final Map<String, String> signatureMapOrig = ProxyClassSignatureHelper.getNonSyntheticSignatureMap(classBeingRedefined);

        reloadFlag = true;

        // TODO: can be single command if scheduler guarantees the keeping execution order in the order of redefinition
        PluginManager.getInstance().getScheduler().scheduleCommand(new ReloadJavaProxyCommand(classLoader, className, signatureMapOrig), 50);
    
<no_super_class>