/**
   * These are the expensive operations (initStandardObjects and compileReader/exec). We do them
   * once here, and define this provider as a singleton, so it's only done at provider creation or
   * whenever rules are refreshed.
   *
   * @param rulesCurator
   */
  private void compileRules(RulesCurator rulesCurator) {
    scriptLock.writeLock().lock();
    try {
      // XXX: we need a principal to access the rules,
      // but pushing and popping system principal could be a bad idea
      Principal systemPrincipal = new SystemPrincipal();
      ResteasyProviderFactory.pushContext(Principal.class, systemPrincipal);
      // Check to see if we need to recompile. we do this inside the write lock
      // just to avoid race conditions where we might double compile
      Date newUpdated = rulesCurator.getUpdated();
      if (newUpdated.equals(this.updated)) {
        return;
      }

      log.debug("Recompiling rules with timestamp: " + newUpdated);

      Context context = Context.enter();
      context.setOptimizationLevel(9);
      scope = context.initStandardObjects(null, true);
      try {
        script = context.compileString(rulesCurator.getRules().getRules(), "rules", 1, null);
        script.exec(context, scope);
        ((ScriptableObject) scope).sealObject();
        this.updated = newUpdated;
      } finally {
        Context.exit();
      }
    } finally {
      ResteasyProviderFactory.popContextData(Principal.class);
      scriptLock.writeLock().unlock();
    }
  }
  @Override
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    final RhinoCompiledScript that = (RhinoCompiledScript) o;

    return compiledScript.equals(that.compiledScript) && engine.equals(that.engine);
  }
 public Object evalScript(Map<String, Object> args, String... scriptStrings) {
   if (scriptStrings == null || scriptStrings.length == 0) {
     return null;
   }
   Context ctx = Context.enter();
   try {
     ctx.setOptimizationLevel(-1);
     Scriptable scope = new NativeObject();
     scope.setParentScope(global);
     setArgs(args, scope);
     for (int i = 0; i < scriptStrings.length; i++) {
       Script script = compileIfNotCompiled(scriptStrings[i], ctx);
       Object result = script.exec(ctx, scope);
       if (i == scriptStrings.length - 1) {
         return result;
       }
     }
     return null;
   } finally {
     Context.exit();
   }
 }
 @Override
 public int hashCode() {
   int result = engine.hashCode();
   result = 31 * result + compiledScript.hashCode();
   return result;
 }