com.atlassian.bamboo.specs.maven.sandbox.SpecsRunner Maven / Gradle / Ivy
package com.atlassian.bamboo.specs.maven.sandbox;
import com.atlassian.bamboo.specs.api.rsbs.RunnerSettings;
import org.apache.maven.plugin.logging.Log;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessControlException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class SpecsRunner {
private final Log log;
private final Collection classFiles;
private final FileToBambooSpecsMapper fileToBambooSpecsMapper;
private final ClassLoader classLoader;
private final Set priorityClasspath;
public SpecsRunner(final Log log, final Collection classFiles, final ClassLoader classloader, final Set priorityClasspath) {
this.log = log;
this.classFiles = classFiles;
this.classLoader = classloader;
this.priorityClasspath = priorityClasspath;
this.fileToBambooSpecsMapper = new FileToBambooSpecsMapper(log, classloader);
}
public Map, Object> runSpecs(final boolean useSecurityManager) {
if (useSecurityManager) {
final ThreadPermissionVerifier permissionVerifier = new LowPrivilegeThreadPermissionVerifier(Paths.get("").toAbsolutePath(), RunnerSettings.getYamlDir());
SecureMethodInvoker.startPerThreadSecurity(
customPermissionVerifiers(),
permissionVerifier);
try {
return SecureMethodInvoker.invoke(this::runSpecsInternal);
} finally {
SecureMethodInvoker.endPerThreadSecurity();
}
} else {
return runSpecsInternal();
}
}
@NotNull
private Map customPermissionVerifiers() {
final Map customVerfiers = new HashMap<>();
try {
final Class> aClass = classLoader.loadClass("com.atlassian.bamboo.specs.util.PrivilegedThreadRegistry");
final Field instance = aClass.getField("INSTANCE");
final Supplier threadSupplier = (Supplier)instance.get(null);
customVerfiers.put(threadSupplier.get(), new ReflectionEnabledThreadPermissionVerifier(classLoader, priorityClasspath));
return customVerfiers;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@NotNull
private Map, Object> runSpecsInternal() {
final List> bambooSpecClasses = classFiles.stream()
.map(fileToBambooSpecsMapper)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
for (final Class> bambooSpecClass : bambooSpecClasses) {
log.info("Running " + bambooSpecClass);
callMainMethod(bambooSpecClass);
}
return Collections.emptyMap();
}
@Nullable
private Object callMainMethod(final Class> aClass) {
final Method mainMethod = getMainMethod(aClass);
if (mainMethod == null) {
log.warn("No public static void main() method in " + aClass);
return null;
}
final Object[] args = {
new String[0]
};
try {
return mainMethod.invoke(null, args);
} catch (final InvocationTargetException | IllegalAccessException e) {
if (e.getCause() instanceof AccessControlException) {
throw (AccessControlException)e.getCause();
}
throw new RuntimeException(e);
}
}
private static Method getMainMethod(final Class> aClass) {
try {
return aClass.getMethod("main", String[].class);
} catch (final NoSuchMethodException ignored) {
return null;
}
}
}