* Do not use Context.setCompileFunctionsWithDynamicScope() as it is

seriously BROKEN for nested functions.
  The only workaround needed is a little fix in HopObject.put() to set the
  parent scope on functions because of the funky way we compile prototypes.
* Use one ContextFactory instance per RhinoCore to initialize, enter and exit
  contexts, and use various call() methods to actually use it in RhinoCore.evaluate()
  and RhinoEngine.invoke().
* Set parent scope in HopObject constructor.
* Use java.lang.ThreadLocal to implement engine/thread registration.
* Implement RhinoCore.getRhinoCore() and RhinoEngine.getRhinoEngine().
* Implement rhino.strictvars to throw errors on undeclared vars.
* Do not declare throws Exception in RhinoCore.processXmlRpc* methods.
* Clean up error logging.
This commit is contained in:
hns 2006-12-20 21:52:22 +00:00
parent 68756f4b3e
commit 20354228a2
6 changed files with 188 additions and 195 deletions

View file

@ -152,9 +152,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
*/ */
public boolean renderSkin(Object skinobj, Object paramobj) public boolean renderSkin(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -170,7 +168,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
Map param = RhinoCore.getSkinParam(paramobj); Map param = RhinoCore.getSkinParam(paramobj);
if (skin != null) { if (skin != null) {
skin.render(reval, null, param); skin.render(engine.reval, null, param);
} }
return true; return true;
@ -186,9 +184,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
*/ */
public String renderSkinAsString(Object skinobj, Object paramobj) public String renderSkinAsString(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -204,9 +200,9 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
Map param = RhinoCore.getSkinParam(paramobj); Map param = RhinoCore.getSkinParam(paramobj);
if (skin != null) { if (skin != null) {
ResponseTrans res = reval.getResponse(); ResponseTrans res = engine.getResponse();
res.pushStringBuffer(); res.pushStringBuffer();
skin.render(reval, null, param); skin.render(engine.reval, null, param);
return res.popStringBuffer(); return res.popStringBuffer();
} }

View file

@ -65,6 +65,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
this(className, core); this(className, core);
this.node = node; this.node = node;
setPrototype(proto); setPrototype(proto);
setParentScope(core.global);
} }
/** /**
@ -72,10 +73,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* *
* @param core the RhinoCore * @param core the RhinoCore
* @return the HopObject prototype * @return the HopObject prototype
* @throws PropertyException
*/ */
public static HopObject init(RhinoCore core) public static HopObject init(RhinoCore core) {
throws PropertyException {
int attributes = DONTENUM | PERMANENT; int attributes = DONTENUM | PERMANENT;
// create prototype object // create prototype object
@ -197,9 +196,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
*/ */
public boolean jsFunction_renderSkin(Object skinobj, Object paramobj) public boolean jsFunction_renderSkin(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -217,7 +214,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
checkNode(); checkNode();
if (skin != null) { if (skin != null) {
skin.render(reval, node, param); skin.render(engine.reval, node, param);
} }
return true; return true;
@ -232,9 +229,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* @return the resource, if found, null otherwise * @return the resource, if found, null otherwise
*/ */
public Object jsFunction_getResource(String resourceName) { public Object jsFunction_getResource(String resourceName) {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine"); Prototype prototype = engine.app.getPrototypeByName(className);
Prototype prototype = engine.core.app.getPrototypeByName(className);
while (prototype != null) { while (prototype != null) {
Resource[] resources = prototype.getResources(); Resource[] resources = prototype.getResources();
for (int i = resources.length - 1; i >= 0; i--) { for (int i = resources.length - 1; i >= 0; i--) {
@ -256,8 +252,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* @return an array of resources with the given name * @return an array of resources with the given name
*/ */
public Object jsFunction_getResources(String resourceName) { public Object jsFunction_getResources(String resourceName) {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Prototype prototype = engine.core.app.getPrototypeByName(className); Prototype prototype = engine.core.app.getPrototypeByName(className);
ArrayList a = new ArrayList(); ArrayList a = new ArrayList();
while (prototype != null) { while (prototype != null) {
@ -282,9 +277,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
*/ */
public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj) public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -302,9 +295,9 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
checkNode(); checkNode();
if (skin != null) { if (skin != null) {
ResponseTrans res = reval.getResponse(); ResponseTrans res = engine.getResponse();
res.pushStringBuffer(); res.pushStringBuffer();
skin.render(reval, node, param); skin.render(engine.reval, node, param);
return res.popStringBuffer(); return res.popStringBuffer();
} }
@ -716,6 +709,13 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
// register property for PropertyRecorder interface // register property for PropertyRecorder interface
if (isRecording) { if (isRecording) {
changedProperties.add(name); changedProperties.add(name);
if (value instanceof Function) {
// reset function's parent scope, needed because of the way we compile
// prototype code, using the prototype objects as scope
Function f = (Function) value;
if (f.getParentScope() == this)
f.setParentScope(core.global);
}
} }
super.put(name, start, value); super.put(name, start, value);
} else { } else {

View file

@ -77,9 +77,7 @@ public class JavaObject extends NativeJavaObject {
*/ */
public boolean renderSkin(Object skinobj, Object paramobj) public boolean renderSkin(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -95,7 +93,7 @@ public class JavaObject extends NativeJavaObject {
Map param = RhinoCore.getSkinParam(paramobj); Map param = RhinoCore.getSkinParam(paramobj);
if (skin != null) { if (skin != null) {
skin.render(reval, javaObject, param); skin.render(engine.reval, javaObject, param);
} }
return true; return true;
@ -111,9 +109,7 @@ public class JavaObject extends NativeJavaObject {
*/ */
public String renderSkinAsString(Object skinobj, Object paramobj) public String renderSkinAsString(Object skinobj, Object paramobj)
throws UnsupportedEncodingException, IOException { throws UnsupportedEncodingException, IOException {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Skin skin; Skin skin;
if (skinobj instanceof Wrapper) { if (skinobj instanceof Wrapper) {
@ -129,9 +125,9 @@ public class JavaObject extends NativeJavaObject {
Map param = RhinoCore.getSkinParam(paramobj); Map param = RhinoCore.getSkinParam(paramobj);
if (skin != null) { if (skin != null) {
ResponseTrans res = reval.getResponse(); ResponseTrans res = engine.getResponse();
res.pushStringBuffer(); res.pushStringBuffer();
skin.render(reval, javaObject, param); skin.render(engine.reval, javaObject, param);
return res.popStringBuffer(); return res.popStringBuffer();
} }
@ -170,11 +166,7 @@ public class JavaObject extends NativeJavaObject {
* Checks whether the given property is defined in this object. * Checks whether the given property is defined in this object.
*/ */
public boolean has(String name, Scriptable start) { public boolean has(String name, Scriptable start) {
// System.err.println ("HAS: "+name); return overload.containsKey(name) || super.has(name, start);
if (overload.containsKey(name)) {
return true;
}
return super.has(name, start);
} }
/** /**
@ -227,8 +219,7 @@ public class JavaObject extends NativeJavaObject {
* @return the resource, if found, null otherwise * @return the resource, if found, null otherwise
*/ */
public Object getResource(String resourceName) { public Object getResource(String resourceName) {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Prototype prototype = engine.core.app.getPrototypeByName(protoName); Prototype prototype = engine.core.app.getPrototypeByName(protoName);
while (prototype != null) { while (prototype != null) {
Resource[] resources = prototype.getResources(); Resource[] resources = prototype.getResources();
@ -251,8 +242,7 @@ public class JavaObject extends NativeJavaObject {
* @return an array of resources with the given name * @return an array of resources with the given name
*/ */
public Object getResources(String resourceName) { public Object getResources(String resourceName) {
Context cx = Context.getCurrentContext(); RhinoEngine engine = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Prototype prototype = engine.core.app.getPrototypeByName(protoName); Prototype prototype = engine.core.app.getPrototypeByName(protoName);
ArrayList a = new ArrayList(); ArrayList a = new ArrayList();
while (prototype != null) { while (prototype != null) {

View file

@ -42,6 +42,9 @@ public final class RhinoCore implements ScopeProvider {
// the application we're running in // the application we're running in
public final Application app; public final Application app;
// our context factory
ContextFactory contextFactory;
// the global object // the global object
GlobalObject global; GlobalObject global;
@ -66,17 +69,20 @@ public final class RhinoCore implements ScopeProvider {
// Any error that may have been found in global code // Any error that may have been found in global code
String globalError; String globalError;
// the debugger, if active
HelmaDebugger debugger = null; HelmaDebugger debugger = null;
// optimization level for rhino engine, ranges from -1 to 9
int optLevel = 0;
// debugger/tracer flags
boolean hasDebugger = false;
boolean hasTracer = false;
// dynamic portion of the type check sleep that grows // dynamic portion of the type check sleep that grows
// as the app remains unchanged // as the app remains unchanged
long updateSnooze = 500; long updateSnooze = 500;
static {
ContextFactory.initGlobal(new HelmaContextFactory());
}
/** /**
* Create a Rhino evaluator for the given application and request evaluator. * Create a Rhino evaluator for the given application and request evaluator.
*/ */
@ -84,6 +90,8 @@ public final class RhinoCore implements ScopeProvider {
this.app = app; this.app = app;
wrappercache = new WeakCacheMap(500); wrappercache = new WeakCacheMap(500);
prototypes = new Hashtable(); prototypes = new Hashtable();
contextFactory = new HelmaContextFactory();
contextFactory.initApplicationClassLoader(app.getClassLoader());
} }
/** /**
@ -91,31 +99,27 @@ public final class RhinoCore implements ScopeProvider {
* necessary to bootstrap the rest is parsed. * necessary to bootstrap the rest is parsed.
*/ */
protected synchronized void initialize() { protected synchronized void initialize() {
Context context = Context.enter();
context.setCompileFunctionsWithDynamicScope(true); hasDebugger = "true".equalsIgnoreCase(app.getProperty("rhino.debug"));
context.setApplicationClassLoader(app.getClassLoader()); hasTracer = "true".equalsIgnoreCase(app.getProperty("rhino.trace"));
wrapper = new WrapMaker();
wrapper.setJavaPrimitiveWrap(false);
context.setWrapFactory(wrapper);
// Set up visual debugger if rhino.debug = true
if ("true".equals(app.getProperty("rhino.debug"))) {
initDebugger(context);
}
// Set default optimization level according to whether debugger is on // Set default optimization level according to whether debugger is on
int optLevel = debugger == null ? 0 : -1; if (hasDebugger || hasTracer) {
optLevel = -1;
String opt = app.getProperty("rhino.optlevel"); } else {
if (opt != null) { String opt = app.getProperty("rhino.optlevel");
try { if (opt != null) {
optLevel = Integer.parseInt(opt); try {
} catch (Exception ignore) { optLevel = Integer.parseInt(opt);
app.logError("Invalid rhino optlevel: " + opt); } catch (Exception ignore) {
app.logError("Invalid rhino optlevel: " + opt);
}
} }
} }
context.setOptimizationLevel(optLevel); wrapper = new WrapMaker();
wrapper.setJavaPrimitiveWrap(false);
Context context = contextFactory.enter();
try { try {
// create global object // create global object
@ -162,29 +166,22 @@ public final class RhinoCore implements ScopeProvider {
getPrototype("global"); getPrototype("global");
} catch (Exception e) { } catch (Exception e) {
System.err.println("Cannot initialize interpreter"); app.logError("Cannot initialize interpreter", e);
System.err.println("Error: " + e);
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e);
} finally { } finally {
Context.exit(); contextFactory.exit();
} }
} }
void initDebugger(Context context) { void initDebugger(Context context) {
try { try {
if (debugger == null) { if (debugger == null) {
debugger = new HelmaDebugger(app.getName()); debugger = new HelmaDebugger(app.getName());
debugger.setScopeProvider(this); debugger.setScopeProvider(this);
// debugger.setScope(global); debugger.attachTo(contextFactory);
debugger.attachTo(context.getFactory()); }
// debugger.pack();
// debugger.getDebugFrame().setLocation(60, 60);
}
// if (!debugger.isVisible())
// debugger.setVisible(true);
} catch (Exception x) { } catch (Exception x) {
x.printStackTrace(); app.logError("Error setting up debugger", x);
} }
} }
@ -235,10 +232,10 @@ public final class RhinoCore implements ScopeProvider {
* @param type the info, containing the object proto, last update time and * @param type the info, containing the object proto, last update time and
* the set of compiled functions properties * the set of compiled functions properties
*/ */
private synchronized void evaluatePrototype(TypeInfo type) { private synchronized void evaluatePrototype(final TypeInfo type) {
type.prepareCompilation(); type.prepareCompilation();
Prototype prototype = type.frameworkProto; final Prototype prototype = type.frameworkProto;
// set the parent prototype in case it hasn't been done before // set the parent prototype in case it hasn't been done before
// or it has changed... // or it has changed...
@ -249,12 +246,16 @@ public final class RhinoCore implements ScopeProvider {
globalError = null; globalError = null;
} }
// loop through the prototype's code elements and evaluate them contextFactory.call(new ContextAction() {
Iterator code = prototype.getCodeResources(); public Object run(Context cx) {
while (code.hasNext()) { // loop through the prototype's code elements and evaluate them
evaluate(type, (Resource) code.next()); Iterator code = prototype.getCodeResources();
} while (code.hasNext()) {
evaluate(cx, type, (Resource) code.next());
}
return null;
}
});
type.commitCompilation(); type.commitCompilation();
} }
@ -470,7 +471,7 @@ public final class RhinoCore implements ScopeProvider {
* Convert an input argument from Java to the scripting runtime * Convert an input argument from Java to the scripting runtime
* representation. * representation.
*/ */
public Object processXmlRpcArgument (Object what) throws Exception { public Object processXmlRpcArgument (Object what) {
if (what == null) if (what == null)
return null; return null;
if (what instanceof Vector) { if (what instanceof Vector) {
@ -506,7 +507,7 @@ public final class RhinoCore implements ScopeProvider {
/** /**
* convert a JavaScript Object object to a generic Java object stucture. * convert a JavaScript Object object to a generic Java object stucture.
*/ */
public Object processXmlRpcResponse (Object what) throws Exception { public Object processXmlRpcResponse (Object what) {
// unwrap if argument is a Wrapper // unwrap if argument is a Wrapper
if (what instanceof Wrapper) { if (what instanceof Wrapper) {
what = ((Wrapper) what).unwrap(); what = ((Wrapper) what).unwrap();
@ -606,9 +607,7 @@ public final class RhinoCore implements ScopeProvider {
HopObject hobj = (HopObject) wrappercache.get(n); HopObject hobj = (HopObject) wrappercache.get(n);
if (hobj == null) { if (hobj == null) {
String protoname = n.getPrototype(); String protoname = n.getPrototype();
Scriptable op = getValidPrototype(protoname); Scriptable op = getValidPrototype(protoname);
// no prototype found for this node // no prototype found for this node
@ -630,7 +629,6 @@ public final class RhinoCore implements ScopeProvider {
} }
hobj = new HopObject(protoname, this, n, op); hobj = new HopObject(protoname, this, n, op);
wrappercache.put(n, hobj); wrappercache.put(n, hobj);
} }
@ -652,12 +650,11 @@ public final class RhinoCore implements ScopeProvider {
if (hasFunction(proto, hrefFunction)) { if (hasFunction(proto, hrefFunction)) {
// get the currently active rhino engine and invoke the function // get the currently active rhino engine and invoke the function
Context cx = Context.getCurrentContext(); RhinoEngine eng = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
Object result; Object result;
try { try {
result = engine.invoke(handler, hrefFunction, result = eng.invoke(handler, hrefFunction,
new Object[] { basicHref }, new Object[] { basicHref },
ScriptingEngine.ARGS_WRAP_DEFAULT, ScriptingEngine.ARGS_WRAP_DEFAULT,
false); false);
@ -689,14 +686,13 @@ public final class RhinoCore implements ScopeProvider {
Skin skin = null; Skin skin = null;
Object handler = obj; Object handler = obj;
// get the currently active rhino engine and render the skin // get the currently active rhino engine and render the skin
Context cx = Context.getCurrentContext(); RhinoEngine eng = RhinoEngine.getRhinoEngine();
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
while (handler != null) { while (handler != null) {
Prototype proto = app.getPrototype(handler); Prototype proto = app.getPrototype(handler);
if (proto != null) { if (proto != null) {
skin = engine.getSkin(proto.getName(), hrefSkin); skin = eng.getSkin(proto.getName(), hrefSkin);
} }
if (skin != null) { if (skin != null) {
@ -707,18 +703,27 @@ public final class RhinoCore implements ScopeProvider {
} }
if (skin != null) { if (skin != null) {
engine.getResponse().pushStringBuffer(); eng.getResponse().pushStringBuffer();
HashMap param = new HashMap(); HashMap param = new HashMap();
param.put("path", basicHref); param.put("path", basicHref);
skin.render(engine.getRequestEvaluator(), handler, param); skin.render(eng.getRequestEvaluator(), handler, param);
basicHref = engine.getResponse().popStringBuffer().trim(); basicHref = eng.getResponse().popStringBuffer().trim();
} }
} }
return basicHref; return basicHref;
} }
/**
* Get the RhinoCore instance associated with the current thread, or null
* @return the RhinoCore instance associated with the current thread
*/
public static RhinoCore getCore() {
RhinoEngine eng = RhinoEngine.getRhinoEngine();
return eng != null ? eng.core : null;
}
///////////////////////////////////////////// /////////////////////////////////////////////
// skin related methods // skin related methods
///////////////////////////////////////////// /////////////////////////////////////////////
@ -766,30 +771,30 @@ public final class RhinoCore implements ScopeProvider {
* @param typename the type this resource belongs to * @param typename the type this resource belongs to
* @param code a code resource * @param code a code resource
*/ */
public void injectCodeResource(String typename, Resource code) { public void injectCodeResource(String typename, final Resource code) {
TypeInfo type = (TypeInfo) prototypes.get(typename.toLowerCase()); final TypeInfo type = (TypeInfo) prototypes.get(typename.toLowerCase());
if (type == null || type.lastUpdate == -1) if (type == null || type.lastUpdate == -1)
return; return;
evaluate(type, code); contextFactory.call(new ContextAction() {
public Object run(Context cx) {
evaluate(cx, type, code);
return null;
}
});
} }
//////////////////////////////////////////////// ////////////////////////////////////////////////
// private evaluation/compilation methods // private evaluation/compilation methods
//////////////////////////////////////////////// ////////////////////////////////////////////////
private synchronized void evaluate(Context cx, TypeInfo type, Resource code) {
private synchronized void evaluate (TypeInfo type, Resource code) {
// get the current context
Context cx = Context.getCurrentContext();
String sourceName = code.getName(); String sourceName = code.getName();
Reader reader = null; Reader reader = null;
Resource previousCurrentResource = app.getCurrentCodeResource(); Resource previousCurrentResource = app.getCurrentCodeResource();
app.setCurrentCodeResource(code); app.setCurrentCodeResource(code);
try { try {
Scriptable op = type.objProto; Scriptable op = type.objProto;
// do the update, evaluating the file // do the update, evaluating the file
if (sourceName.endsWith(".js")) { if (sourceName.endsWith(".js")) {
reader = new InputStreamReader(code.getInputStream()); reader = new InputStreamReader(code.getInputStream());
@ -805,11 +810,12 @@ public final class RhinoCore implements ScopeProvider {
} }
} catch (Exception e) { } catch (Exception e) {
app.logError("Error parsing file " + sourceName, e); ScriptingException sx = new ScriptingException(e.getMessage(), e);
app.logError("Error parsing file " + sourceName, sx);
// mark prototype as broken // mark prototype as broken
if (type.error == null) { if (type.error == null) {
type.error = e.getMessage(); type.error = e.getMessage();
if (type.error == null || e instanceof EcmaError) { if (type.error == null) {
type.error = e.toString(); type.error = e.toString();
} }
if ("global".equals(type.frameworkProto.getLowerCaseName())) { if ("global".equals(type.frameworkProto.getLowerCaseName())) {
@ -817,7 +823,6 @@ public final class RhinoCore implements ScopeProvider {
} }
wrappercache.clear(); wrappercache.clear();
} }
// e.printStackTrace();
} finally { } finally {
app.setCurrentCodeResource(previousCurrentResource); app.setCurrentCodeResource(previousCurrentResource);
if (reader != null) { if (reader != null) {
@ -931,7 +936,7 @@ public final class RhinoCore implements ScopeProvider {
objProto.setAttributes(key, 0); objProto.setAttributes(key, 0);
objProto.delete(key); objProto.delete(key);
} catch (Exception px) { } catch (Exception px) {
System.err.println("Error unsetting property "+key+" on "+ app.logEvent("Error unsetting property "+key+" on "+
frameworkProto.getName()); frameworkProto.getName());
} }
} }
@ -1036,7 +1041,6 @@ public final class RhinoCore implements ScopeProvider {
} }
public Scriptable wrapNewObject(Context cx, Scriptable scope, Object obj) { public Scriptable wrapNewObject(Context cx, Scriptable scope, Object obj) {
// System.err.println ("N-Wrapping: "+obj);
if (obj instanceof INode) { if (obj instanceof INode) {
return getNodeWrapper((INode) obj); return getNodeWrapper((INode) obj);
} }
@ -1092,13 +1096,30 @@ public final class RhinoCore implements ScopeProvider {
} }
} }
} class HelmaContextFactory extends ContextFactory {
class HelmaContextFactory extends ContextFactory { final boolean strictVars = "true".equalsIgnoreCase(app.getProperty("strictVars"));
protected boolean hasFeature(Context cx, int featureIndex) {
if (featureIndex == Context.FEATURE_DYNAMIC_SCOPE) { protected void onContextCreated(Context cx) {
return true; cx.setWrapFactory(wrapper);
cx.setOptimizationLevel(optLevel);
// Set up visual debugger if rhino.debug = true
if (hasDebugger)
initDebugger(cx);
super.onContextCreated(cx);
} }
return super.hasFeature(cx, featureIndex);
protected boolean hasFeature(Context cx, int featureIndex) {
switch (featureIndex) {
case Context.FEATURE_DYNAMIC_SCOPE:
return true;
case Context.FEATURE_STRICT_VARS:
return strictVars;
default:
return super.hasFeature(cx, featureIndex);
}
}
} }
} }

View file

@ -54,6 +54,8 @@ public class RhinoEngine implements ScriptingEngine {
// the request evaluator instance owning this fesi evaluator // the request evaluator instance owning this fesi evaluator
RequestEvaluator reval; RequestEvaluator reval;
// the rhino core
RhinoCore core; RhinoCore core;
// remember global variables from last invokation to be able to // remember global variables from last invokation to be able to
@ -66,6 +68,9 @@ public class RhinoEngine implements ScriptingEngine {
// the thread currently running this engine // the thread currently running this engine
Thread thread; Thread thread;
// thread local engine registry
static ThreadLocal engines = new ThreadLocal();
// the introspector that provides documentation for this application // the introspector that provides documentation for this application
DocApplication doc = null; DocApplication doc = null;
@ -83,9 +88,8 @@ public class RhinoEngine implements ScriptingEngine {
this.app = app; this.app = app;
this.reval = reval; this.reval = reval;
initRhinoCore(app); initRhinoCore(app);
context = Context.enter();
context.setCompileFunctionsWithDynamicScope(true); context = core.contextFactory.enter();
context.setApplicationClassLoader(app.getClassLoader());
try { try {
global = new GlobalObject(core, app, true); global = new GlobalObject(core, app, true);
@ -105,22 +109,27 @@ public class RhinoEngine implements ScriptingEngine {
extensionGlobals.putAll(tmpGlobals); extensionGlobals.putAll(tmpGlobals);
} }
} catch (ConfigurationException e) { } catch (ConfigurationException e) {
app.logEvent("Couldn't initialize extension " + ext.getName() + ": " + app.logError("Couldn't initialize extension " + ext.getName(), e);
e.getMessage());
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println("Cannot initialize interpreter"); app.logError("Cannot initialize interpreter", e);
System.err.println("Error: " + e); throw new RuntimeException(e.getMessage(), e);
e.printStackTrace();
throw new RuntimeException(e.getMessage());
} finally { } finally {
Context.exit (); core.contextFactory.exit ();
} }
} }
/**
* Return the RhinoEngine associated with the current thread, or null.
* @return the RhinoEngine assocated with the current thread
*/
public static RhinoEngine getRhinoEngine() {
return (RhinoEngine) engines.get();
}
/** /**
* Initialize the RhinoCore instance for this engine and application. * Initialize the RhinoCore instance for this engine and application.
* @param app the application we belong to * @param app the application we belong to
@ -145,39 +154,20 @@ public class RhinoEngine implements ScriptingEngine {
* engine know it should update its prototype information. * engine know it should update its prototype information.
*/ */
public void updatePrototypes() throws IOException { public void updatePrototypes() throws IOException {
// remember the current thread as our thread - we this here so // remember the current thread as our thread - we do this here so
// the thread is already set when the RequestEvaluator calls // the thread is already set when the RequestEvaluator calls
// Application.getDataRoot(), which may result in a function invocation // Application.getDataRoot(), which may result in a function invocation
// (chicken and egg problem, kind of) // (chicken and egg problem, kind of)
thread = Thread.currentThread(); thread = Thread.currentThread();
context = Context.enter(); context = core.contextFactory.enter();
context.setCompileFunctionsWithDynamicScope(true);
context.setApplicationClassLoader(app.getClassLoader());
context.setWrapFactory(core.wrapper);
// if visual debugger is on let it know we're entering a context if (core.hasTracer) {
if (core.debugger != null) {
core.initDebugger(context);
}
if ("true".equals(app.getProperty("rhino.trace"))) {
context.setDebugger(new Tracer(getResponse()), null); context.setDebugger(new Tracer(getResponse()), null);
} }
// Set default optimization level according to whether debugger is on // register the engine with the current thread
int optLevel = core.debugger == null ? 0 : -1; engines.set(this);
try {
optLevel = Integer.parseInt(app.getProperty("rhino.optlevel"));
} catch (Exception ignore) {
// use default opt-level
}
context.setOptimizationLevel(optLevel);
// register the per-thread scope with the dynamic scope
context.putThreadLocal("reval", reval);
context.putThreadLocal("engine", this);
// update prototypes // update prototypes
core.updatePrototypes(); core.updatePrototypes();
} }
@ -224,10 +214,9 @@ public class RhinoEngine implements ScriptingEngine {
* execution context has terminated. * execution context has terminated.
*/ */
public synchronized void exitContext() { public synchronized void exitContext() {
context.removeThreadLocal("reval"); // unregister the engine threadlocal
context.removeThreadLocal("engine"); engines.remove();
Context.exit(); core.contextFactory.exit();
// core.global.unregisterScope();
thread = null; thread = null;
// loop through previous globals and unset them, if necessary. // loop through previous globals and unset them, if necessary.
@ -237,7 +226,7 @@ public class RhinoEngine implements ScriptingEngine {
try { try {
global.delete(g); global.delete(g);
} catch (Exception x) { } catch (Exception x) {
System.err.println("Error resetting global property: " + g); app.logEvent("Error unsetting global property: " + g);
} }
} }
lastGlobals = null; lastGlobals = null;
@ -265,23 +254,7 @@ public class RhinoEngine implements ScriptingEngine {
public Object invoke(Object thisObject, String functionName, Object[] args, public Object invoke(Object thisObject, String functionName, Object[] args,
int argsWrapMode, boolean resolve) throws ScriptingException { int argsWrapMode, boolean resolve) throws ScriptingException {
try { try {
for (int i = 0; i < args.length; i++) {
switch (argsWrapMode) {
case ARGS_WRAP_DEFAULT:
// convert java objects to JavaScript
if (args[i] != null) {
args[i] = Context.javaToJS(args[i], global);
}
break;
case ARGS_WRAP_XMLRPC:
// XML-RPC requires special argument conversion
args[i] = core.processXmlRpcArgument(args[i]);
break;
}
}
Scriptable obj = thisObject == null ? global : Context.toObject(thisObject, global); Scriptable obj = thisObject == null ? global : Context.toObject(thisObject, global);
// if function name should be resolved interpret it as member expression, // if function name should be resolved interpret it as member expression,
// otherwise replace dots with underscores. // otherwise replace dots with underscores.
if (resolve) { if (resolve) {
@ -308,7 +281,23 @@ public class RhinoEngine implements ScriptingEngine {
return null; return null;
} }
Object retval = ((Function) f).call(context, global, obj, args); for (int i = 0; i < args.length; i++) {
switch (argsWrapMode) {
case ARGS_WRAP_DEFAULT:
// convert java objects to JavaScript
if (args[i] != null) {
args[i] = Context.javaToJS(args[i], global);
}
break;
case ARGS_WRAP_XMLRPC:
// XML-RPC requires special argument conversion
args[i] = core.processXmlRpcArgument(args[i]);
break;
}
}
// use Context.call() in order to set the context's factory
Object retval = Context.call(core.contextFactory, (Function)f, global, obj, args);
if (retval instanceof Wrapper) { if (retval instanceof Wrapper) {
retval = ((Wrapper) retval).unwrap(); retval = ((Wrapper) retval).unwrap();
@ -449,7 +438,6 @@ public class RhinoEngine implements ScriptingEngine {
return prop; return prop;
} }
} catch (Exception esx) { } catch (Exception esx) {
// System.err.println ("Error in getProperty: "+esx);
return null; return null;
} }
} }
@ -479,7 +467,7 @@ public class RhinoEngine implements ScriptingEngine {
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public void serialize(Object obj, OutputStream out) throws IOException { public void serialize(Object obj, OutputStream out) throws IOException {
Context.enter(); core.contextFactory.enter();
try { try {
// use a special ScriptableOutputStream that unwraps Wrappers // use a special ScriptableOutputStream that unwraps Wrappers
ScriptableOutputStream sout = new ScriptableOutputStream(out, core.global) { ScriptableOutputStream sout = new ScriptableOutputStream(out, core.global) {
@ -492,7 +480,7 @@ public class RhinoEngine implements ScriptingEngine {
sout.writeObject(obj); sout.writeObject(obj);
sout.flush(); sout.flush();
} finally { } finally {
Context.exit(); core.contextFactory.exit();
} }
} }
@ -506,12 +494,12 @@ public class RhinoEngine implements ScriptingEngine {
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public Object deserialize(InputStream in) throws IOException, ClassNotFoundException { public Object deserialize(InputStream in) throws IOException, ClassNotFoundException {
Context.enter(); core.contextFactory.enter();
try { try {
ObjectInputStream sin = new ScriptableInputStream(in, core.global); ObjectInputStream sin = new ScriptableInputStream(in, core.global);
return sin.readObject(); return sin.readObject();
} finally { } finally {
Context.exit(); core.contextFactory.exit();
} }
} }

View file

@ -54,7 +54,7 @@ public class XmlRpcObject extends BaseFunction {
this.method = method; this.method = method;
} }
/** /**
* This method is used as HopObject constructor from JavaScript. * This method is used as HopObject constructor from JavaScript.
*/ */
public static Object xmlrpcObjectConstructor(Context cx, Object[] args, public static Object xmlrpcObjectConstructor(Context cx, Object[] args,
@ -106,20 +106,18 @@ public class XmlRpcObject extends BaseFunction {
throw new EvaluatorException("Invalid method name"); throw new EvaluatorException("Invalid method name");
} }
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine"); RhinoCore core = RhinoCore.getCore();
RhinoCore c = engine.getCore();
Scriptable retval = null; Scriptable retval = null;
try { try {
retval = Context.getCurrentContext().newObject(c.getScope()); retval = Context.getCurrentContext().newObject(core.getScope());
XmlRpcClient client = new XmlRpcClient(url); XmlRpcClient client = new XmlRpcClient(url);
// long now = System.currentTimeMillis ();
int l = args.length; int l = args.length;
Vector v = new Vector(); Vector v = new Vector();
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
Object arg = c.processXmlRpcResponse(args[i]); Object arg = core.processXmlRpcResponse(args[i]);
v.addElement(arg); v.addElement(arg);
} }
@ -129,7 +127,7 @@ public class XmlRpcObject extends BaseFunction {
if (result instanceof Exception) { if (result instanceof Exception) {
throw (Exception) result; throw (Exception) result;
} }
retval.put("result", retval, c.processXmlRpcArgument(result)); retval.put("result", retval, core.processXmlRpcArgument(result));
} catch (Exception x) { } catch (Exception x) {
String msg = x.getMessage(); String msg = x.getMessage();