com.appland.appmap.transform.annotations.HookFactory Maven / Gradle / Ivy
package com.appland.appmap.transform.annotations;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.appland.appmap.util.Logger;
import javassist.CtBehavior;
public class HookFactory {
private static final List> AGENT_METHOD_FACTORIES =
new ArrayList>() {
{
add(HookAnnotatedSystem::from);
add(HookClassSystem::from);
}
};
private static final List> APP_METHOD_FACTORIES =
new ArrayList>() {
{
add(HookConditionSystem::from);
}
};
private static final List> ALL_METHOD_FACTORIES =
new ArrayList>() {
{
addAll(AGENT_METHOD_FACTORIES);
addAll(APP_METHOD_FACTORIES);
}
};
public static final HookFactory AGENT_HOOKS_FACTORY = new HookFactory(AGENT_METHOD_FACTORIES);
public static final HookFactory APP_HOOKS_FACTORY = new HookFactory(APP_METHOD_FACTORIES);
public static final HookFactory ALL_HOOKS_FACTORY = new HookFactory(ALL_METHOD_FACTORIES);
private List> requiredHookSystemFactories = new ArrayList<>();
private final static List> optionalSystemFactories =
new ArrayList>() {
{
add(ExcludeReceiverSystem::from);
add(ArgumentArraySystem::from);
}
};
private HookFactory(List> hookSystemFactories) {
requiredHookSystemFactories.addAll(hookSystemFactories);
}
/**
* Creates a Hook from code behavior.
*
* @return a new Hook object if hookBehavior is a valid hook, null otherwise
*/
public Hook from(CtBehavior hookBehavior) {
SourceMethodSystem sourceSystem = null;
for (Function factoryFn : requiredHookSystemFactories) {
sourceSystem = (SourceMethodSystem)factoryFn.apply(hookBehavior);
if (sourceSystem != null) {
break;
}
}
if (sourceSystem == null) {
return null;
}
List optionalSystems = optionalSystemFactories
.stream()
.map(factoryFn -> factoryFn.apply(hookBehavior))
.filter(Objects::nonNull)
.collect(Collectors.toList());
Hook hook = new Hook(sourceSystem, optionalSystems, hookBehavior);
for (ISystem optionalSystem : optionalSystems) {
if (!optionalSystem.validate(hook)) {
Logger.println("hook "
+ hook
+ " failed validation from "
+ optionalSystem.getClass().getSimpleName());
return null;
}
}
return hook;
}
}