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

com.newrelic.weave.utils.ClassCache Maven / Gradle / Ivy

There is a newer version: 8.17.0
Show newest version
/*
 *
 *  * Copyright 2020 New Relic Corporation. All rights reserved.
 *  * SPDX-License-Identifier: Apache-2.0
 *
 */

package com.newrelic.weave.utils;

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Finds and caches class information using a {@link ClassFinder}, to be used during a transformation. This class is
 * threadsafe.
 */
public class ClassCache implements ClassInformationFinder {

    private static final byte[] NO_CLASS_BYTES = new byte[] {};
    private static final ClassInformation NO_CLASS_INFORMATION = new ClassInformation();

    private final ClassFinder classFinder;
    private final ConcurrentMap classExistsCache = new ConcurrentHashMap<>();
    private final ConcurrentMap classBytesCache = new ConcurrentHashMap<>();
    private final ConcurrentMap classInformationCache = new ConcurrentHashMap<>();

    public ClassCache(ClassFinder classFinder) {
        this.classFinder = classFinder;
    }

    /**
     * Determine whether or not the specified class can be resolved using the cache's {@link ClassFinder}. Results of
     * this method are cached.
     * 
     * @param internalName internal class name
     * @return true if the resource can be resovled, false otherwise
     */
    public boolean hasClassResource(String internalName) {
        Boolean result = classExistsCache.get(internalName);
        if (result != null) {
            return result;
        }

        URL resource = classFinder.findResource(internalName);
        boolean hasResource = resource != null;
        classExistsCache.putIfAbsent(internalName, hasResource);
        return hasResource;
    }

    /**
     * Get the byte[] representing the specified class using the cache's {@link ClassFinder}. Results of this method are
     * cached.
     * 
     * @param internalName internal class name
     * @return class bytes, or null if the class could not be found
     * @throws IOException
     */
    public byte[] getClassResource(String internalName) throws IOException {
        byte[] result = classBytesCache.get(internalName);
        if (result != null) {
            return result == NO_CLASS_BYTES ? null : result;
        }

        URL resource = classFinder.findResource(internalName);
        if (resource == null) {
            classBytesCache.putIfAbsent(internalName, NO_CLASS_BYTES);
            return null;
        }

        result = Streams.read(resource.openStream(), true);
        classBytesCache.putIfAbsent(internalName, result);
        return result;
    }

    /**
     * Find the {@link ClassInformation} for the specified internal class name. Results of this method are cached.
     * 
     * @param internalName internal class name
     * @return the {@link ClassInformation} for the specified internal class name
     * @throws IOException
     */
    public ClassInformation getClassInformation(String internalName) throws IOException {
        ClassInformation result = classInformationCache.get(internalName);
        if (result != null) {
            return result == NO_CLASS_INFORMATION ? null : result;
        }

        byte[] classBytes = getClassResource(internalName);
        if (classBytes == null) {
            classInformationCache.putIfAbsent(internalName, NO_CLASS_INFORMATION);
            return null;
        }

        result = ClassInformation.fromClassBytes(classBytes);
        classInformationCache.putIfAbsent(internalName, result);
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy