/** * 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(); } }
public JsRunner get() { /* * Create a new thread/request local javascript scope for the JsRules, * based on the preinitialized global one (which contains our js rules). */ // Avoid a write lock if we can if (!rulesCurator.getUpdated().equals(this.updated)) { compileRules(this.rulesCurator); } Scriptable rulesScope; scriptLock.readLock().lock(); try { Context context = Context.enter(); rulesScope = context.newObject(scope); rulesScope.setPrototype(scope); rulesScope.setParentScope(null); Context.exit(); } finally { scriptLock.readLock().unlock(); } return new JsRunner(rulesScope); }