package edu.mit.simile.butterfly;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class represents the "scope" of that is given to a javascript controller
* and contains all the various objects that the controller might need
* to interact with the system.
*/
public class ButterflyScope extends ScriptableObject {
private static final long serialVersionUID = -7468104001568307817L;
protected static final Logger _logger = LoggerFactory.getLogger("butterfly.scope");
public ButterflyScope(ButterflyModule module, Context context) throws Exception {
_logger.trace("> new ButterflyScope for module: {}", module.getName());
// first, get a juicy top level scope that contains all the ECMA
// objects and some Java related utility methods that Rhino provides
Scriptable scope = new ImporterTopLevel(context);
// make the "ButteflyModule" object available to this scope
defineClass(scope, ScriptableButterfly.class);
// and set this scope as our prototype
setPrototype(scope);
// We want this to be a new top-level scope, so set its
// parent scope to null. This means that any variables created
// by assignments will be properties of this.
setParentScope(null);
// We need to create an instance of the ButterflyModule object and
// inject it into this scope. We keep a reference to this instance
// because it's what we'll need to know if the controller has responded
// to the request or not
final Object[] args = {};
ScriptableButterfly _scriptableButterfly = (ScriptableButterfly) context.newObject(this, ScriptableButterfly.getName(), args);
_scriptableButterfly.init(module);
_scriptableButterfly.setParentScope(this);
super.put("butterfly", this, _scriptableButterfly);
super.put("module", this, module);
prepareScope(context, scope, module);
_logger.trace("< new ButterflyScope for module: {}", module.getName());
}
private void prepareScope(Context context, Scriptable scope, ButterflyModule module) throws Exception {
_logger.trace("> prepareScope({})", module.getName());
Map<String,ButterflyModule> dependencies = module.getDependencies();
for (ButterflyModule m : dependencies.values()) {
prepareScope(context, scope, m);
}
Set<ButterflyScriptableObject> scriptables = module.getScriptables();
final Object[] args = {};
// make the scriptable classes available to this scope
// (both as classes and instances)
Iterator<ButterflyScriptableObject> i = scriptables.iterator();
while (i.hasNext()) {
ButterflyScriptableObject c = i.next();
defineClass(scope, c.getClass());
_logger.debug("defined class: {}", c.getClassName());
ButterflyScriptableObject scriptable = (ButterflyScriptableObject) context.newObject(this, c.getClassName(), args);
scriptable.init(module);
scriptable.setParentScope(this);
Set<String> implementations = module.getImplementations();
for (String name : implementations) {
super.put(name, this, scriptable);
_logger.debug("defined instance: {}", name);
}
}
_logger.trace("< prepareScope({})", module.getName());
}
public String getClassName() {
return "ButterflyScope";
}
}