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

com.appland.appmap.record.EventTemplateRegistry Maven / Gradle / Ivy

package com.appland.appmap.record;

import com.appland.appmap.config.Properties;
import com.appland.appmap.output.v1.CodeObject;
import com.appland.appmap.output.v1.Event;
import com.appland.appmap.output.v1.Value;
import com.appland.appmap.util.Logger;
import javassist.CtBehavior;

import java.util.ArrayList;
import java.util.List;

/**
 * Stores events as templates built from behaviors intended to be hooked. Hooks can then access and
 * clone these templates before storing runtime information to be recorded. This caches event data at Class load time
 * rather than grabbing it through reflection every time a hook is invoked. It has benefits for DRY as well as
 * for performance.
 */
public class EventTemplateRegistry {
  private static final EventTemplateRegistry instance = new EventTemplateRegistry();
  private static final Recorder recorder = Recorder.getInstance();

  private final List eventTemplates = new ArrayList<>();

  private EventTemplateRegistry() { }

  public static EventTemplateRegistry get() {
    return EventTemplateRegistry.instance;
  }

  /**
   * Creates and stores an {@link Event} template built from a behavior. The behavior will also
   * have a {@link CodeObject} registered with the global {@link Recorder} instance.
   * @param behavior The behavior to create a template from
   * @return A behavior ordinal (an index to the event template)
   */
  public Integer register(CtBehavior behavior, String[] labels) {
    Event event = new Event(behavior);
    return this.register(event, behavior, labels);
  }

  /**
   * Stores an event template built previously from a behavior. The behavior will also
   * have a {@link CodeObject} registered with the global {@link Recorder} instance.
   * @param event The {@link Event} template to be registered
   * @param behavior The behavior used to create the {@link Event} template
   * @return The behavior ordinal (an index to the {@link Event} template)
   */
  public synchronized Integer register(Event event, CtBehavior behavior, String[] labels) {
    recorder.registerCodeObject(CodeObject.createTree(behavior, labels));
    eventTemplates.add(event);
    return eventTemplates.size() - 1;
  }

  /**
   * Retrieve an {@link Event} template by ordinal.
   * @param templateId The behavior ordinal returned when the template was registered
   * @return An {@link Event} template if one exists at the given index. Otherwise, null.
   */
  public Event getTemplate(Integer templateId) {
    try {
      return eventTemplates.get(templateId);
    } catch (IndexOutOfBoundsException e) {
      // fall through
    }
    return null;
  }

  /**
   * Clones an {@link Event} template and sets the {@code event} field.
   * @param templateId The behavior ordinal
   * @return A copy of the event template with the {@code event} field set
   * @throws UnknownEventException If no template exists for the behavior ordinal given
   */
  public Event buildCallEvent(int templateId) {
    Event eventTemplate = lookupEventTemplate(templateId);
    Event event = Event.functionCallEvent(eventTemplate);
    for (Value param : eventTemplate.parameters) {
      event.addParameter(param);
    }
    return event;
  }

  /**
   * Prepares a return event.
   */
  public Event buildReturnEvent(int templateId) {
    Event eventTemplate = lookupEventTemplate(templateId);
    return Event.functionReturnEvent(eventTemplate);
  }

  Event lookupEventTemplate(int templateId) {
    try {
      return eventTemplates.get(templateId);
    } catch (IndexOutOfBoundsException e) {
      final String msg = String.format("unknown template for ordinal %d - have we been loaded by a non-system class loader?", templateId);

      if (Properties.DebugHooks) {
        Logger.println(msg);
        Logger.println(e);
      }

      throw new UnknownEventException(msg);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy