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

com.teamscale.jacoco.agent.commit_resolution.git_properties.GitPropertiesLocatingTransformer Maven / Gradle / Ivy

package com.teamscale.jacoco.agent.commit_resolution.git_properties;

import com.teamscale.jacoco.agent.util.LoggingUtils;
import com.teamscale.report.util.ClasspathWildcardIncludeFilter;
import org.conqat.lib.commons.string.StringUtils;
import org.slf4j.Logger;

import java.io.File;
import java.lang.instrument.ClassFileTransformer;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * {@link ClassFileTransformer} that doesn't change the loaded classes but searches their corresponding Jar/War/Ear/...
 * files for a git.properties file.
 */
public class GitPropertiesLocatingTransformer implements ClassFileTransformer {

	private final Logger logger = LoggingUtils.getLogger(this);
	private final Set seenJars = new ConcurrentSkipListSet<>();
	private final IGitPropertiesLocator locator;
	private final ClasspathWildcardIncludeFilter locationIncludeFilter;

	public GitPropertiesLocatingTransformer(IGitPropertiesLocator locator,
											ClasspathWildcardIncludeFilter locationIncludeFilter) {
		this.locator = locator;
		this.locationIncludeFilter = locationIncludeFilter;
	}

	@Override
	public byte[] transform(ClassLoader classLoader, String className, Class aClass,
							ProtectionDomain protectionDomain, byte[] classFileContent) {
		if (protectionDomain == null) {
			// happens for e.g. java.lang. We can ignore these classes
			return null;
		}

		if (StringUtils.isEmpty(className) || !locationIncludeFilter.isIncluded(className)) {
			// only search in jar files of included classes
			return null;
		}

		try {
			CodeSource codeSource = protectionDomain.getCodeSource();
			if (codeSource == null || codeSource.getLocation() == null) {
				// unknown when this can happen, we suspect when code is generated at runtime
				// but there's nothing else we can do here in either case.
				// codeSource.getLocation() is null e.g. when executing Pixelitor with Java14 for class sun/reflect/misc/Trampoline
				logger.debug("Could not locate code source for class {}. Skipping git.properties search for this class",
						className);
				return null;
			}

			URL jarOrClassFolderUrl = codeSource.getLocation();
			File searchRoot = GitPropertiesLocatorUtils.extractGitPropertiesSearchRoot(jarOrClassFolderUrl);
			if (searchRoot == null) {
				logger.warn("Not searching location for git.properties with unknown protocol or extension {}." +
								" If this location contains your git.properties, please report this warning as a" +
								" bug to CQSE. In that case, auto-discovery of git.properties will not work.",
						jarOrClassFolderUrl);
				return null;
			}

			if (hasLocationAlreadyBeenSearched(searchRoot)) {
				return null;
			}

			logger.debug("Scheduling asynchronous search for git.properties in {}", searchRoot);
			locator.searchJarFileForGitPropertiesAsync(searchRoot);
		} catch (Throwable e) {
			// we catch Throwable to be sure that we log all errors as anything thrown from this method is
			// silently discarded by the JVM
			logger.error("Failed to process class {} in search of git.properties", className, e);
		}
		return null;
	}

	private boolean hasLocationAlreadyBeenSearched(File location) {
		return !seenJars.add(location.toString());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy