content: package org.lightfish.business.escalation.control;
  
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import javax.annotation.PostConstruct;
  import javax.ejb.Singleton;
  import javax.enterprise.event.Event;
  import javax.enterprise.event.Observes;
  import javax.inject.Inject;
  import javax.script.Bindings;
  import javax.script.ScriptEngine;
  import javax.script.ScriptEngineManager;
  import javax.script.ScriptException;
  import org.lightfish.business.escalation.entity.Escalation;
  import org.lightfish.business.escalation.entity.Script;
  import org.lightfish.business.logging.Log;
  import org.lightfish.business.servermonitoring.boundary.Severity;
  import org.lightfish.business.servermonitoring.entity.Snapshot;
  
  /**
   *
   * @author adam bien, adam-bien.com
   */
  @Singleton
  public class SnapshotEscalator {
  
      private static final String ENGINE_NAME = "JavaScript";
      Map<String,Snapshot> recentSnapshots = new HashMap<>();
      ScriptEngine scriptEngine;
      @Inject
      Log LOG;
      @Inject
      ScriptStore scripting;
      @Inject
      EscalationMessageProcessor messageProcessor;
      @Inject
      @Severity(Severity.Level.ESCALATION)
      Event<Escalation> escalationSink;
  
      @PostConstruct
      public void initScripting() {
          
          ScriptEngineManager engineManager = new ScriptEngineManager();
          this.scriptEngine = engineManager.getEngineByName(ENGINE_NAME);
          if (this.scriptEngine == null) {
              throw new IllegalStateException("Cannot create ScriptEngine: " + ENGINE_NAME);
          }
          LOG.info("Loaded script engine: " + ENGINE_NAME);
      }
  
      public void escalate(@Observes @Severity(Severity.Level.HEARTBEAT) Snapshot current) {
          List<Script> scripts = this.scripting.activeScripts();
          try {
              Bindings binding = this.scriptEngine.createBindings();
              binding.put("current", current);
              Snapshot recent = this.recentSnapshots.get(current.getInstanceName());
              binding.put("previous", recent);
              long start = System.currentTimeMillis();
              try {
                  if (recent != null) {
                      for (Script script : scripts) {
                          Object retVal = null;
                          try {
                              final String content = script.getContent();
                              if(content == null)
                                  return;
                              retVal = this.scriptEngine.eval(content, binding);
                          } catch (ScriptException scriptException) {
                              LOG.error("Cannot evaluate script: " + script, scriptException);
                          }
                          if (canBeConvertedToTrue(retVal)) {
                              String basicMessage = messageProcessor.processBasicMessage(script.getBasicMessage(), current);
                              String richMessage = messageProcessor.processRichMessage(script.getRichMessage(), current);
                              Escalation escalation = new Escalation.Builder()
                                      .channel(script.getName())
                                      .basicMessage(basicMessage)
                                      .richMessage(richMessage)
                                      .snapshot(current)
                                      .build();
                              escalationSink.fire(escalation);
                              LOG.info("Escalated: " + script + " for snapshot: " + current + " and recent: " + recentSnapshots);
                          }
                      }
                  }
  
              } finally {
                  LOG.info("Performance: " + (System.currentTimeMillis() - start));
              }
              this.recentSnapshots.put(current.getInstanceName(), current);
          } catch (Exception e) {
              throw new IllegalStateException("Exception during script evaluation: " + e, e);
          }
      }
  
      boolean canBeConvertedToTrue(Object retVal) {
          if (retVal == null) {
              return false;
          }
          if (!(retVal instanceof Boolean)) {
              return false;
          }
          return (boolean) retVal;
      }
  }
  