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

com.appland.appmap.transform.annotations.SourceMethodSystem Maven / Gradle / Ivy

package com.appland.appmap.transform.annotations;

import java.util.Map;

import org.tinylog.TaggedLogger;

import com.appland.appmap.config.AppMapConfig;
import com.appland.appmap.output.v1.Parameters;
import com.appland.appmap.output.v1.Value;

import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public abstract class SourceMethodSystem extends BaseSystem {
  private static final TaggedLogger logger = AppMapConfig.getLogger(null);

  public static final String EVENT_TOKEN = "$evt";

  private String hookClass;
  private String hookMethod;
  private MethodEvent methodEvent;

  protected SourceMethodSystem(CtBehavior behavior, Class annotationClass) {
    super(behavior);
    this.hookClass = behavior.getDeclaringClass().getName();
    this.hookMethod = behavior.getName();
    this.methodEvent = (MethodEvent)AnnotationUtil.getObject(behavior,
      annotationClass, "methodEvent",
      MethodEvent.METHOD_INVOCATION);    
  }

  public Boolean match(CtBehavior behavior, Map mapResult) {
    return false;
  }

  public String getKey() {
    return null;
  }

  @Override
  public String toString() {
    return String.format("%s.%s", this.hookClass, this.hookMethod);
  }

  @Override
  public void mutateStaticParameters(CtBehavior hookBehavior, Parameters hookParameters) {
    hookParameters.add(new Value().setName(EVENT_TOKEN));
  }

  @Override
  public void mutateRuntimeParameters(HookBinding binding, Parameters runtimeParameters) {
    if (this.methodEvent == MethodEvent.METHOD_RETURN) {
      final CtBehavior targetBehavior = binding.getTargetBehavior();
      if (targetBehavior.getMethodInfo().isMethod()) {
        try {
          CtMethod method = (CtMethod) targetBehavior;
          CtClass returnType = method.getReturnType();
          Value returnValue = new Value();

          if (returnType == CtClass.voidType) {
            returnValue.setName("null");
          } else {
            returnValue.setName("com.appland.appmap.process.RuntimeUtil.boxValue($_)");
          }

          runtimeParameters.add(returnValue);
        } catch (NotFoundException e) {
          // getReturnType throws a NotFoundException when the class of the
          // returned value can't be found. See the note in the Parameters
          // constructor describing why we should be able to ignore this.
          logger.debug(e, "unknown return type");
        }
      }
    } else if (this.methodEvent == MethodEvent.METHOD_EXCEPTION) {
      runtimeParameters.add(new Value()
          .setClassType("java.lang.Throwable")
          .setName("$e"));
    }
  }

  public MethodEvent getMethodEvent() {
    return methodEvent;
  }

  @Override
  public Integer getParameterPriority() {
    return 200;
  }

  @Override
  public Integer getHookPosition() {
    final MethodEvent methodEvent = getMethodEvent();
    switch (methodEvent) {
    case METHOD_INVOCATION:
      return ISystem.HOOK_POSITION_FIRST;
    case METHOD_RETURN:
    case METHOD_EXCEPTION:
      return ISystem.HOOK_POSITION_LAST;
    default:
      // If somehow another method event type gets used, it's imperative that
      // this method get updated. So, throw an exception to indicate that
      // there's a problem.
      throw new RuntimeException("Unknown MethodEvent type (" + methodEvent.getEventString() + "," + methodEvent.getIndex() + ")");
    }
  }  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy