package com.nominanuda.rhino; import static org.mozilla.javascript.RhinoHelper.RHINO; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.mozilla.javascript.Context; import org.mozilla.javascript.RhinoEmbedding; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import com.nominanuda.zen.obj.JsonDeserializer; import com.nominanuda.rhino.host.SourceModuleFactory; public abstract class AbsScriptSource implements IScriptSource { private final static SourceModuleFactory MODS = new SourceModuleFactory(); private final Map<String, Object> hostObjs = new HashMap<String, Object>(); private String jsSuffix = ".js", jsonSuffix = ".json"; private RhinoEmbedding rhinoEmbedding; private ScriptableObject cachedScope; public abstract String source(boolean doReset) throws IOException; protected abstract Script script(Context cx, String source, boolean doSave); @Override public void setHostObject(String key, Object obj) { hostObjs.put(key, obj); } @Override public IScript open(String source, boolean doSave) throws Exception { final Context cx = rhinoEmbedding.enterContext(); if (cachedScope == null) { cachedScope = RHINO.createTopScope(cx, false); for (Entry<String, Object> hostObj : hostObjs.entrySet()) { cachedScope.defineProperty(hostObj.getKey(), resolveHostObject(hostObj.getValue(), cx, cachedScope), ScriptableObject.DONTENUM | ScriptableObject.READONLY); } } Scriptable ctrlScope = RHINO.protocloneScriptable(cx, cachedScope); RHINO.evaluateScript(script(cx, source, doSave), cx, ctrlScope); return new ScriptWrapper(cx, ctrlScope, source(false)); } @Override public IScript open(String source) throws Exception { return open(source, false); } @Override public IScript open() throws Exception { return open(null, false); } @Override public IScript reset() throws Exception { source(true); return open(); } /* host objs smartness */ private Object resolveHostObject(Object value, Context cx, Scriptable scope) throws Exception { if (value instanceof String) { String string = (String) value; if (string.endsWith(jsSuffix)) { return MODS.create(string, null, scope, cx); } if (string.endsWith(jsonSuffix)) { return JsonDeserializer.JSON_DESERIALIZER.deserialize((new URL(string).openStream())); } } return value; } /* setters */ public void setRhinoEmbedding(RhinoEmbedding rhinoEmbedding) { this.rhinoEmbedding = rhinoEmbedding; } public void setHostObjects(Map<String, Object> objs) { if (objs != null) { for (Entry<String, Object> entry: objs.entrySet()) { setHostObject(entry.getKey(), entry.getValue()); } } } public void setJsSuffix(String suffix) { jsSuffix = suffix; } public void setJsonSuffix(String suffix) { jsonSuffix = suffix; } }