class ScriptedDecideRule extends DecideRule 
implements ApplicationContextAware, InitializingBean {
    private static final long serialVersionUID = 3L;

    private static final Logger logger =
        Logger.getLogger(ScriptedDecideRule.class.getName());
    
    /** engine name; default "beanshell" */
    protected String engineName = "beanshell";
    public String getEngineName() {
        return this.engineName;
    }
    public void setEngineName(String name) {
        this.engineName = name;
    }
    
    protected ReadSource scriptSource = null;
    public ReadSource getScriptSource() {
        return scriptSource;
    }
    @Required
    public void setScriptSource(ReadSource scriptSource) {
        this.scriptSource = scriptSource;
    }

    /**
     * Whether each ToeThread should get its own independent script 
     * engine, or they should share synchronized access to one 
     * engine. Default is true, meaning each thread gets its own 
     * isolated engine.
     */
    protected boolean isolateThreads = true; 
    public boolean getIsolateThreads() {
        return isolateThreads;
    }
    public void setIsolateThreads(boolean isolateThreads) {
        this.isolateThreads = isolateThreads;
    }

    protected ApplicationContext appCtx;
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.appCtx = applicationContext;
    }

    transient protected ThreadLocal<ScriptEngine> threadEngine = 
        new ThreadLocal<ScriptEngine>();
    transient protected ScriptEngine sharedEngine;

    public ScriptedDecideRule() {
    }
    
    public void afterPropertiesSet() throws Exception {
        // fail at build-time if script engine not available
        if(null == new ScriptEngineManager().getEngineByName(engineName)) {
            throw new BeanInitializationException("named ScriptEngine not available");
        }
    }
    @Override
    public DecideResult innerDecide(CrawlURI uri) {
        // depending on previous configuration, engine may 
        // be local to this thread or shared
        ScriptEngine engine = getEngine(); 
        synchronized(engine) {
            // synchronization is harmless for local thread engine,
            // necessary for shared engine
            try {
                engine.put("object",uri);
                engine.put("appCtx", appCtx);
                return (DecideResult)engine.eval("decisionFor(object)");
            } catch (ScriptException e) {
                logger.log(Level.WARNING,e.getMessage(),e);
                return DecideResult.NONE;
            } finally {
                engine.put("object", null);
                engine.put("appCtx", null);
            }
        }
    }

    /**
     * Get the proper ScriptEngine instance -- either shared or local 
     * to this thread. 
     * @return ScriptEngine to use
     */
    protected ScriptEngine getEngine() {<FILL_FUNCTION_BODY>}

    /**
     * Create a new ScriptEngine instance, preloaded with any supplied
     * source file and the variables 'self' (this ScriptedDecideRule) 
     * and 'context' (the ApplicationContext). 
     * 
     * @return  the new Interpreter instance
     */
    protected ScriptEngine newEngine() {
        ScriptEngine interpreter = new ScriptEngineManager().getEngineByName(engineName);

        interpreter.put("self", this);
        interpreter.put("context", appCtx);
        
        Reader reader = null;
        try {
            reader = getScriptSource().obtainReader();
            interpreter.eval(reader);
        } catch (ScriptException e) {
            logger.log(Level.SEVERE,"script problem",e);
        } finally {
            IOUtils.closeQuietly(reader);
        }

        return interpreter; 
    }
    
    
}

        if (getIsolateThreads()) {
            ScriptEngine engine = threadEngine.get();
            if (engine == null) {
                engine = newEngine();
                threadEngine.set(engine);
            }
            return engine;
        } else {
            // sharing the engine
            synchronized (this) {
                if (sharedEngine == null) {
                    sharedEngine = newEngine();
                }
            }
            return sharedEngine;
        }
    
<methods>public void <init>() ,public boolean accepts(org.archive.modules.CrawlURI) ,public org.archive.modules.deciderules.DecideResult decisionFor(org.archive.modules.CrawlURI) ,public java.lang.String getComment() ,public boolean getEnabled() ,public org.archive.spring.KeyedProperties getKeyedProperties() ,public org.archive.modules.deciderules.DecideResult onlyDecision(org.archive.modules.CrawlURI) ,public void setComment(java.lang.String) ,public void setEnabled(boolean) <variables>protected java.lang.String comment,protected org.archive.spring.KeyedProperties kp