Added code for Rhino scripting engine.
This commit is contained in:
parent
78411bea50
commit
1ea945f82a
8 changed files with 2822 additions and 0 deletions
283
src/helma/scripting/rhino/GlobalObject.java
Normal file
283
src/helma/scripting/rhino/GlobalObject.java
Normal file
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import helma.util.HtmlEncoder;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class GlobalObject extends ScriptableObject {
|
||||
Application app;
|
||||
RhinoCore core;
|
||||
|
||||
/**
|
||||
* Creates a new GlobalObject object.
|
||||
*
|
||||
* @param core ...
|
||||
* @param app ...
|
||||
*
|
||||
* @throws PropertyException ...
|
||||
*/
|
||||
public GlobalObject(RhinoCore core, Application app)
|
||||
throws PropertyException {
|
||||
this.core = core;
|
||||
this.app = app;
|
||||
|
||||
String[] globalFuncs = {
|
||||
"renderSkin", "renderSkinAsString", "getProperty",
|
||||
"authenticate", "createSkin", "format", "encode",
|
||||
"encodeXml", "encodeForm", "stripTags"
|
||||
};
|
||||
|
||||
defineFunctionProperties(globalFuncs, GlobalObject.class, 0);
|
||||
put("app", this, new ApplicationBean(app));
|
||||
put("Xml", this, new XmlObject(core));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String getClassName() {
|
||||
return "GlobalObject";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean renderSkin(Object skin, Object param) {
|
||||
// System.err.println ("RENDERSKIN CALLED WITH PARAM "+param);
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(null, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Object obj = sp.get(ids[i].toString(), sp);
|
||||
if (obj instanceof NativeJavaObject) {
|
||||
p.put(ids[i], ((NativeJavaObject) obj).unwrap());
|
||||
} else {
|
||||
p.put(ids[i], obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
s.render(reval, null, p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String renderSkinAsString(Object skin, Object param) {
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(null, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Object obj = sp.get(ids[i].toString(), sp);
|
||||
if (obj instanceof NativeJavaObject) {
|
||||
p.put(ids[i], ((NativeJavaObject) obj).unwrap());
|
||||
} else {
|
||||
p.put(ids[i], obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
reval.res.pushStringBuffer();
|
||||
s.render(reval, null, p);
|
||||
|
||||
return reval.res.popStringBuffer();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param propname ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String getProperty(String propname) {
|
||||
return app.getProperty(propname);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param user ...
|
||||
* @param pwd ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean authenticate(String user, String pwd) {
|
||||
return app.authenticate(user, pwd);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Skin createSkin(String str) {
|
||||
return new Skin(str, app);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String encode(String str) {
|
||||
return HtmlEncoder.encodeAll(str);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String encodeXml(String str) {
|
||||
return HtmlEncoder.encodeXml(str);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String encodeForm(String str) {
|
||||
return HtmlEncoder.encodeFormValue(str);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String format(String str) {
|
||||
return HtmlEncoder.encode(str);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String stripTags(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
char[] c = str.toCharArray();
|
||||
boolean inTag = false;
|
||||
int i;
|
||||
int j = 0;
|
||||
|
||||
for (i = 0; i < c.length; i++) {
|
||||
if (c[i] == '<') {
|
||||
inTag = true;
|
||||
}
|
||||
|
||||
if (!inTag) {
|
||||
if (i > j) {
|
||||
c[j] = c[i];
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
if (c[i] == '>') {
|
||||
inTag = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > j) {
|
||||
return new String(c, 0, j);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
738
src/helma/scripting/rhino/HopObject.java
Normal file
738
src/helma/scripting/rhino/HopObject.java
Normal file
|
@ -0,0 +1,738 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class HopObject extends ScriptableObject {
|
||||
static Method hopObjCtor;
|
||||
|
||||
static {
|
||||
Method[] methods = HopObject.class.getMethods();
|
||||
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if ("hopObjectConstructor".equals(methods[i].getName())) {
|
||||
hopObjCtor = methods[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String className;
|
||||
INode node;
|
||||
RhinoCore core;
|
||||
|
||||
/**
|
||||
* Creates a new HopObject object.
|
||||
*/
|
||||
public HopObject() {
|
||||
className = "HopObject";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HopObject object.
|
||||
*
|
||||
* @param cname ...
|
||||
*/
|
||||
public HopObject(String cname) {
|
||||
className = cname;
|
||||
}
|
||||
|
||||
// public void jsConstructor () {
|
||||
|
||||
/* Context cx = Context.getCurrentContext ();
|
||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal ("engine");
|
||||
core = engine.core;
|
||||
node = new helma.objectmodel.db.Node (null, null, core.app.getWrappedNodeManager ()); */
|
||||
|
||||
// }
|
||||
public static Object hopObjectConstructor(Context cx, Object[] args,
|
||||
Function ctorObj, boolean inNewExpr) {
|
||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||
RhinoCore c = engine.core;
|
||||
String prototype = ((FunctionObject) ctorObj).getFunctionName();
|
||||
INode n = new helma.objectmodel.db.Node(prototype, prototype,
|
||||
c.app.getWrappedNodeManager());
|
||||
HopObject hobj = new HopObject(prototype);
|
||||
|
||||
hobj.init(c, n);
|
||||
|
||||
return hobj;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param c ...
|
||||
* @param n ...
|
||||
*/
|
||||
public void init(RhinoCore c, INode n) {
|
||||
core = c;
|
||||
node = n;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object jsGet_cache() {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return node.getCacheNode();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean jsFunction_renderSkin(Object skin, Object param) {
|
||||
// System.err.println ("RENDERSKIN CALLED WITH PARAM "+param);
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(node, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Object obj = sp.get(ids[i].toString(), sp);
|
||||
if (obj instanceof NativeJavaObject) {
|
||||
p.put(ids[i], ((NativeJavaObject) obj).unwrap());
|
||||
} else {
|
||||
p.put(ids[i], obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
s.render(reval, node, p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String jsFunction_renderSkinAsString(Object skin, Object param) {
|
||||
// System.err.println ("RENDERSKIN CALLED WITH PARAM "+param);
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(node, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Object obj = sp.get(ids[i].toString(), sp);
|
||||
if (obj instanceof NativeJavaObject) {
|
||||
p.put(ids[i], ((NativeJavaObject) obj).unwrap());
|
||||
} else {
|
||||
p.put(ids[i], obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
reval.res.pushStringBuffer();
|
||||
s.render(reval, node, p);
|
||||
|
||||
return reval.res.popStringBuffer();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param action ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object jsFunction_href(Object action) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String act = null;
|
||||
|
||||
if (action != null) {
|
||||
if (action instanceof NativeJavaObject) {
|
||||
act = ((NativeJavaObject) action).unwrap().toString();
|
||||
} else if (!(action instanceof Undefined)) {
|
||||
act = action.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return core.app.getNodeHref(node, act);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param id ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object jsFunction_get(Object id) {
|
||||
if ((node == null) || (id == null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Context cx = Context.getCurrentContext();
|
||||
Object n = null;
|
||||
|
||||
if (id instanceof Number) {
|
||||
n = node.getSubnodeAt(((Number) id).intValue());
|
||||
} else {
|
||||
n = node.getChildElement(id.toString());
|
||||
}
|
||||
|
||||
if (n == null) {
|
||||
return null;
|
||||
} else {
|
||||
return cx.toObject(n, core.global);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public int jsFunction_count() {
|
||||
if (node == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return node.numberOfNodes();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public int jsFunction_size() {
|
||||
return jsFunction_count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch child objects from (relational) database.
|
||||
*/
|
||||
public void jsFunction_prefetchChildren() {
|
||||
jsFunction_prefetchChildren(0, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch child objects from (relational) database.
|
||||
*/
|
||||
public void jsFunction_prefetchChildren(int start, int length) {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
((helma.objectmodel.db.Node) node).prefetchChildren(start, length);
|
||||
} catch (Exception x) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object[] jsFunction_list() {
|
||||
int l = node.numberOfNodes();
|
||||
Enumeration e = node.getSubnodes();
|
||||
ArrayList a = new ArrayList();
|
||||
|
||||
while ((e != null) && e.hasMoreElements()) {
|
||||
a.add(e.nextElement());
|
||||
}
|
||||
|
||||
return a.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param child ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean jsFunction_add(Object child) {
|
||||
if ((node == null) || (child == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child instanceof HopObject) {
|
||||
INode added = node.addNode(((HopObject) child).node);
|
||||
|
||||
return true;
|
||||
} else if (child instanceof INode) {
|
||||
INode added = node.addNode((INode) child);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param index ...
|
||||
* @param child ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean jsFunction_addAt(int index, Object child) {
|
||||
if (child == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child instanceof HopObject) {
|
||||
INode added = node.addNode(((HopObject) child).node, index);
|
||||
|
||||
return true;
|
||||
} else if (child instanceof INode) {
|
||||
INode added = node.addNode((INode) child, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove node itself or one or more subnodes.
|
||||
*/
|
||||
public boolean jsFunction_remove(Object child) {
|
||||
// semantics: if called without arguments, remove self.
|
||||
// otherwise, remove given subnodes.
|
||||
if (child == null) {
|
||||
return node.remove();
|
||||
} else if (node != null) {
|
||||
try {
|
||||
if (child instanceof HopObject) {
|
||||
HopObject hobj = (HopObject) child;
|
||||
|
||||
if (hobj.node != null) {
|
||||
node.removeNode(hobj.node);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception x) {
|
||||
System.err.println("XXX: " + x);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the node itself or a subnode
|
||||
*/
|
||||
public boolean jsFunction_invalidate(String childId) {
|
||||
if (node instanceof helma.objectmodel.db.Node) {
|
||||
if (childId == null) {
|
||||
((helma.objectmodel.db.Node) node).invalidate();
|
||||
} else {
|
||||
((helma.objectmodel.db.Node) node).invalidateNode(childId);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if node is contained in subnodes
|
||||
*/
|
||||
public int jsFunction_contains(Object obj) {
|
||||
if ((node != null) && (obj != null) && obj instanceof HopObject) {
|
||||
return node.contains(((HopObject) obj).node);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
* @param value ...
|
||||
*/
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
if (node == null) {
|
||||
super.put(name, start, value);
|
||||
} else {
|
||||
if (value instanceof NativeJavaObject) {
|
||||
value = ((NativeJavaObject) value).unwrap();
|
||||
}
|
||||
|
||||
if ((value == null) || (value == Undefined.instance)) {
|
||||
node.unset(name);
|
||||
} else if (value instanceof Scriptable) {
|
||||
Scriptable s = (Scriptable) value;
|
||||
|
||||
if ("Date".equals(s.getClassName())) {
|
||||
node.setDate(name, new Date((long) ScriptRuntime.toNumber(s)));
|
||||
} else {
|
||||
node.setString(name, s.toString());
|
||||
}
|
||||
} else if (value instanceof String) {
|
||||
node.setString(name, value.toString());
|
||||
} else if (value instanceof Boolean) {
|
||||
node.setBoolean(name, ((Boolean) value).booleanValue());
|
||||
} else if (value instanceof Number) {
|
||||
node.setFloat(name, ((Number) value).doubleValue());
|
||||
} else if (value instanceof Date) {
|
||||
node.setDate(name, (Date) value);
|
||||
} else if (value instanceof INode) {
|
||||
node.setNode(name, (INode) value);
|
||||
} else if (value instanceof HopObject) {
|
||||
node.setNode(name, ((HopObject) value).node);
|
||||
} else {
|
||||
node.setJavaObject(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean has(String name, Scriptable start) {
|
||||
if (super.has(name, start)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((prototype != null) && prototype.has(name, start)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((node != null) && (node.get(name) != null)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
*/
|
||||
public void delete(String name) {
|
||||
if ((node != null)) {
|
||||
node.unset(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object get(String name, Scriptable start) {
|
||||
// System.err.println ("GET from "+node+": "+name);
|
||||
Object retval = super.get(name, start);
|
||||
|
||||
if (retval != ScriptableObject.NOT_FOUND) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (prototype != null) {
|
||||
retval = prototype.get(name, start);
|
||||
}
|
||||
|
||||
if (retval != ScriptableObject.NOT_FOUND) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
// Everything starting with an underscore is interpreted as internal property
|
||||
if (name.startsWith("_")) {
|
||||
return getInternalProperty(name);
|
||||
}
|
||||
|
||||
IProperty p = node.get(name);
|
||||
|
||||
if (p != null) {
|
||||
if (p.getType() == IProperty.STRING) {
|
||||
return p.getStringValue();
|
||||
}
|
||||
|
||||
if (p.getType() == IProperty.BOOLEAN) {
|
||||
return p.getBooleanValue() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
if (p.getType() == IProperty.INTEGER) {
|
||||
return new Long(p.getIntegerValue());
|
||||
}
|
||||
|
||||
if (p.getType() == IProperty.FLOAT) {
|
||||
return new Double(p.getFloatValue());
|
||||
}
|
||||
|
||||
Context cx = Context.getCurrentContext();
|
||||
|
||||
if (p.getType() == IProperty.DATE) {
|
||||
Date d = p.getDateValue();
|
||||
|
||||
if (d == null) {
|
||||
return NOT_FOUND;
|
||||
} else {
|
||||
Object[] args = { new Long(d.getTime()) };
|
||||
try {
|
||||
return cx.newObject(core.global, "Date", args);
|
||||
} catch (PropertyException px) {
|
||||
return NOT_FOUND;
|
||||
} catch (NotAFunctionException nafx) {
|
||||
return NOT_FOUND;
|
||||
} catch (JavaScriptException nafx) {
|
||||
return NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p.getType() == IProperty.NODE) {
|
||||
INode n = p.getNodeValue();
|
||||
|
||||
if (n == null) {
|
||||
return NOT_FOUND;
|
||||
} else {
|
||||
return cx.toObject(n, core.global);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.getType() == IProperty.JAVAOBJECT) {
|
||||
Object obj = p.getJavaObjectValue();
|
||||
|
||||
if (obj == null) {
|
||||
return NOT_FOUND;
|
||||
} else {
|
||||
return cx.toObject(obj, core.global);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// as last resort, try to get property as anonymous subnode
|
||||
Object anon = node.getChildElement(name);
|
||||
|
||||
if (anon != null) {
|
||||
return anon;
|
||||
}
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
private Object getInternalProperty(String name) {
|
||||
if ("__id__".equals(name) || "_id".equals(name)) {
|
||||
return node.getID();
|
||||
}
|
||||
|
||||
if ("__prototype__".equals(name) || "_prototype".equals(name)) {
|
||||
return node.getPrototype();
|
||||
}
|
||||
|
||||
if ("__parent__".equals(name) || "_parent".equals(name)) {
|
||||
return core.getNodeWrapper(node.getParent());
|
||||
}
|
||||
|
||||
// some more internal properties
|
||||
if ("__name__".equals(name)) {
|
||||
return node.getName();
|
||||
}
|
||||
|
||||
if ("__fullname__".equals(name)) {
|
||||
return node.getFullName();
|
||||
}
|
||||
|
||||
if ("__hash__".equals(name)) {
|
||||
return Integer.toString(node.hashCode());
|
||||
}
|
||||
|
||||
if ("__node__".equals(name)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if ("__created__".equalsIgnoreCase(name)) {
|
||||
return new Date(node.created());
|
||||
}
|
||||
|
||||
if ("__lastmodified__".equalsIgnoreCase(name)) {
|
||||
return new Date(node.lastModified());
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object[] getIds() {
|
||||
if (node == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
Enumeration enum = node.properties();
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
while (enum.hasMoreElements())
|
||||
list.add(enum.nextElement());
|
||||
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean has(int idx, Scriptable start) {
|
||||
if (node != null) {
|
||||
return (0 <= idx && idx < node.numberOfNodes());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object get(int idx, Scriptable start) {
|
||||
if (node != null) {
|
||||
INode n = node.getSubnodeAt(idx);
|
||||
|
||||
if (n == null) {
|
||||
return NOT_FOUND;
|
||||
} else {
|
||||
Context cx = Context.getCurrentContext();
|
||||
return cx.toObject(n, core.global);
|
||||
}
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param hint ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object getDefaultValue(Class hint) {
|
||||
return (className != null) ? ("[HopObject " + className + "]") : "[HopObject]";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String toString() {
|
||||
return (className != null) ? ("[HopObject " + className + "]") : "[HopObject]";
|
||||
}
|
||||
}
|
176
src/helma/scripting/rhino/JavaObject.java
Normal file
176
src/helma/scripting/rhino/JavaObject.java
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class JavaObject extends NativeJavaObject {
|
||||
|
||||
RhinoCore core;
|
||||
Scriptable prototype;
|
||||
|
||||
/**
|
||||
* Creates a new JavaObject wrapper.
|
||||
*/
|
||||
public JavaObject(Scriptable scope, Object obj, Scriptable prototype) {
|
||||
this.parent = scope;
|
||||
this.javaObject = obj;
|
||||
this.prototype = prototype;
|
||||
staticType = obj.getClass();
|
||||
initMembers();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean jsFunction_renderSkin(Object skin, Object param) {
|
||||
// System.err.println ("RENDERSKIN CALLED WITH PARAM "+param);
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(javaObject, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++)
|
||||
p.put(ids[i], sp.get(ids[i].toString(), sp));
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
s.render(reval, javaObject, p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param skin ...
|
||||
* @param param ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String jsFunction_renderSkinAsString(Object skin, Object param) {
|
||||
// System.err.println ("RENDERSKIN CALLED WITH PARAM "+param);
|
||||
Context cx = Context.getCurrentContext();
|
||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||
Skin s;
|
||||
|
||||
if (skin instanceof Skin) {
|
||||
s = (Skin) skin;
|
||||
} else {
|
||||
s = core.app.getSkin(javaObject, skin.toString(), null);
|
||||
}
|
||||
|
||||
Map p = null;
|
||||
|
||||
if ((param != null) && (param != Undefined.instance)) {
|
||||
p = new HashMap();
|
||||
|
||||
if (param instanceof Scriptable) {
|
||||
Scriptable sp = (Scriptable) param;
|
||||
Object[] ids = sp.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++)
|
||||
p.put(ids[i], sp.get(ids[i].toString(), sp));
|
||||
}
|
||||
}
|
||||
|
||||
if (s != null) {
|
||||
reval.res.pushStringBuffer();
|
||||
s.render(reval, javaObject, p);
|
||||
|
||||
return reval.res.popStringBuffer();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param action ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object jsFunction_href(Object action) {
|
||||
if (javaObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String act = null;
|
||||
|
||||
if (action != null) {
|
||||
if (action instanceof NativeJavaObject) {
|
||||
act = ((NativeJavaObject) action).unwrap().toString();
|
||||
} else if (!(action instanceof Undefined)) {
|
||||
act = action.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return core.app.getNodeHref(javaObject, act);
|
||||
}
|
||||
|
||||
public boolean has(String name, Scriptable start) {
|
||||
System.err.println ("HAS: "+name);
|
||||
if (prototype.has(name, start))
|
||||
return true;
|
||||
return super.has(name, start);
|
||||
}
|
||||
|
||||
public Object get(String name, Scriptable start) {
|
||||
System.err.println ("GET: "+name);
|
||||
Object obj = prototype.get(name, start);
|
||||
if (obj != null && obj != Undefined.instance)
|
||||
return obj;
|
||||
return super.get(name, start);
|
||||
}
|
||||
|
||||
}
|
139
src/helma/scripting/rhino/MapWrapper.java
Normal file
139
src/helma/scripting/rhino/MapWrapper.java
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.NativeJavaObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MapWrapper extends ScriptableObject {
|
||||
Map map;
|
||||
RhinoCore core;
|
||||
|
||||
/**
|
||||
* Creates a new MapWrapper object.
|
||||
*/
|
||||
public MapWrapper() {
|
||||
map = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MapWrapper object.
|
||||
*
|
||||
* @param map ...
|
||||
* @param core ...
|
||||
*/
|
||||
public MapWrapper(Map map, RhinoCore core) {
|
||||
this.map = map;
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
* @param value ...
|
||||
*/
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
}
|
||||
|
||||
if (value instanceof NativeJavaObject) {
|
||||
map.put(name, ((NativeJavaObject) value).unwrap());
|
||||
} else {
|
||||
map.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object get(String name, Scriptable start) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object obj = map.get(name);
|
||||
|
||||
if (obj != null) {
|
||||
Context cx = Context.getCurrentContext();
|
||||
|
||||
return cx.toObject(obj, core.global);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
* @param start ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public boolean has(String name, Scriptable start) {
|
||||
return (map != null) && map.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param name ...
|
||||
*/
|
||||
public void delete(String name) {
|
||||
if (map != null) {
|
||||
map.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object[] getIds() {
|
||||
if (map == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
return map.keySet().toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String getClassName() {
|
||||
return "[MapWrapper]";
|
||||
}
|
||||
}
|
84
src/helma/scripting/rhino/RhinoActionAdapter.java
Normal file
84
src/helma/scripting/rhino/RhinoActionAdapter.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.scripting.*;
|
||||
|
||||
// import java.util.Vector;
|
||||
// import java.util.Iterator;
|
||||
import java.io.*;
|
||||
|
||||
// import helma.framework.*;
|
||||
// import helma.framework.core.*;
|
||||
// import helma.util.Updatable;
|
||||
|
||||
/**
|
||||
* An class that updates fesi interpreters with actionfiles and templates.
|
||||
*/
|
||||
public class RhinoActionAdapter {
|
||||
String sourceName;
|
||||
String function;
|
||||
String functionAsString;
|
||||
|
||||
/**
|
||||
* Creates a new RhinoActionAdapter object.
|
||||
*
|
||||
* @param action ...
|
||||
*/
|
||||
public RhinoActionAdapter(ActionFile action) {
|
||||
String content = action.getContent();
|
||||
String functionName = action.getFunctionName();
|
||||
|
||||
sourceName = action.toString();
|
||||
function = composeFunction(functionName,
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
content);
|
||||
|
||||
// check if this is a template and we need to generate an "_as_string" variant
|
||||
if (action instanceof Template) {
|
||||
functionAsString = composeFunction(functionName + "_as_string",
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
"res.pushStringBuffer(); " + content +
|
||||
"\r\nreturn res.popStringBuffer();\r\n");
|
||||
} else {
|
||||
functionAsString = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected String composeFunction(String funcname, String params, String body) {
|
||||
if ((body == null) || "".equals(body.trim())) {
|
||||
body = ";\r\n";
|
||||
} else {
|
||||
body = body + "\r\n";
|
||||
}
|
||||
|
||||
if (params == null) {
|
||||
params = "";
|
||||
}
|
||||
|
||||
StringBuffer f = new StringBuffer("function ");
|
||||
|
||||
f.append(funcname);
|
||||
f.append(" (");
|
||||
f.append(params);
|
||||
f.append(") {\n");
|
||||
f.append(body);
|
||||
f.append("\n}");
|
||||
|
||||
return f.toString();
|
||||
}
|
||||
}
|
686
src/helma/scripting/rhino/RhinoCore.java
Normal file
686
src/helma/scripting/rhino/RhinoCore.java
Normal file
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.main.Server;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.Relation;
|
||||
import helma.scripting.*;
|
||||
import helma.util.CacheMap;
|
||||
import helma.util.Updatable;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This is the implementation of ScriptingEnvironment for the Mozilla Rhino EcmaScript interpreter.
|
||||
*/
|
||||
public final class RhinoCore implements WrapHandler {
|
||||
// the application we're running in
|
||||
public final Application app;
|
||||
|
||||
// the global object
|
||||
Scriptable global;
|
||||
|
||||
// caching table for JavaScript object wrappers
|
||||
CacheMap wrappercache;
|
||||
|
||||
// table containing JavaScript prototypes
|
||||
Hashtable prototypes;
|
||||
long lastUpdate = 0;
|
||||
|
||||
/**
|
||||
* Create a Rhino evaluator for the given application and request evaluator.
|
||||
*/
|
||||
public RhinoCore(Application app) {
|
||||
this.app = app;
|
||||
wrappercache = new CacheMap(500, .75f);
|
||||
prototypes = new Hashtable();
|
||||
|
||||
Context context = Context.enter();
|
||||
|
||||
context.setCompileFunctionsWithDynamicScope(true);
|
||||
context.setWrapHandler(this);
|
||||
|
||||
int optLevel = 0;
|
||||
|
||||
try {
|
||||
optLevel = Integer.parseInt(app.getProperty("rhino.optlevel"));
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
// System.err.println("Setting Rhino optlevel to " + optLevel);
|
||||
context.setOptimizationLevel(optLevel);
|
||||
|
||||
try {
|
||||
GlobalObject g = new GlobalObject(this, app);
|
||||
|
||||
global = context.initStandardObjects(g);
|
||||
ScriptableObject.defineClass(global, HopObject.class);
|
||||
putPrototype("hopobject",
|
||||
ScriptableObject.getClassPrototype(global, "HopObject"));
|
||||
putPrototype("global", global);
|
||||
initialize();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Cannot initialize interpreter");
|
||||
System.err.println("Error: " + e);
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} finally {
|
||||
context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the evaluator, making sure the minimum type information
|
||||
* necessary to bootstrap the rest is parsed.
|
||||
*/
|
||||
private synchronized void initialize() {
|
||||
Collection protos = app.getPrototypes();
|
||||
|
||||
for (Iterator i = protos.iterator(); i.hasNext();) {
|
||||
Prototype proto = (Prototype) i.next();
|
||||
|
||||
initPrototype(proto);
|
||||
}
|
||||
|
||||
// always fully initialize global prototype, because
|
||||
// we always need it and there's no chance to trigger
|
||||
// creation on demand.
|
||||
getPrototype("global");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a prototype without fully parsing its script files.
|
||||
*/
|
||||
synchronized void initPrototype(Prototype prototype) {
|
||||
// System.err.println ("FESI INIT PROTO "+prototype);
|
||||
Scriptable op = null;
|
||||
String name = prototype.getName();
|
||||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
Scriptable opp = null;
|
||||
Prototype parent = prototype.getParentPrototype();
|
||||
|
||||
if (parent != null) {
|
||||
// see if parent prototype is already registered. if not, register it
|
||||
opp = getRawPrototype(parent.getName());
|
||||
|
||||
if (opp == null) {
|
||||
initPrototype(parent);
|
||||
opp = getRawPrototype(parent.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (!"global".equalsIgnoreCase(name) && !"hopobject".equalsIgnoreCase(name) &&
|
||||
(opp == null)) {
|
||||
if (app.isJavaPrototype(name)) {
|
||||
opp = getRawPrototype("__javaobject__");
|
||||
} else {
|
||||
opp = getRawPrototype("hopobject");
|
||||
}
|
||||
}
|
||||
|
||||
// if prototype doesn't exist (i.e. is a standard prototype built by HopExtension), create it.
|
||||
op = getRawPrototype(name);
|
||||
|
||||
if (op == null) {
|
||||
try {
|
||||
Context context = Context.getCurrentContext();
|
||||
|
||||
op = new HopObject(name); // context.newObject (global /*, "HopObject" */);
|
||||
op.setPrototype(opp);
|
||||
op.setParentScope(global);
|
||||
op.put("prototypename", op, name);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error creating prototype: " + ignore);
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
|
||||
putPrototype(name, op);
|
||||
} else {
|
||||
// set parent prototype just in case it has been changed
|
||||
op.setPrototype(opp);
|
||||
}
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a new prototyped hopobject and then calls
|
||||
// the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase(name) && !"root".equalsIgnoreCase(name)) {
|
||||
try {
|
||||
FunctionObject fp = new FunctionObject(name, HopObject.hopObjCtor, global);
|
||||
|
||||
fp.addAsConstructor(global, op);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error adding ctor for " + name + ": " + ignore);
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a prototype, parsing and compiling all its script files.
|
||||
*/
|
||||
synchronized void evaluatePrototype(Prototype prototype) {
|
||||
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
|
||||
Scriptable op = null;
|
||||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
Scriptable opp = null;
|
||||
Prototype parent = prototype.getParentPrototype();
|
||||
|
||||
if (parent != null) {
|
||||
// see if parent prototype is already registered. if not, register it
|
||||
opp = getPrototype(parent.getName());
|
||||
|
||||
if (opp == null) {
|
||||
evaluatePrototype(parent);
|
||||
opp = getPrototype(parent.getName());
|
||||
}
|
||||
}
|
||||
|
||||
String name = prototype.getName();
|
||||
|
||||
if (!"global".equalsIgnoreCase(name) && !"hopobject".equalsIgnoreCase(name) &&
|
||||
(opp == null)) {
|
||||
if (app.isJavaPrototype(name)) {
|
||||
opp = getPrototype("__javaobject__");
|
||||
} else {
|
||||
opp = getPrototype("hopobject");
|
||||
}
|
||||
}
|
||||
|
||||
// if prototype doesn't exist (i.e. is a standard prototype built by HopExtension), create it.
|
||||
op = getPrototype(name);
|
||||
|
||||
if (op == null) {
|
||||
try {
|
||||
Context context = Context.getCurrentContext();
|
||||
|
||||
op = new HopObject(name); // context.newObject (global /*, "HopObject" */);
|
||||
op.setPrototype(opp);
|
||||
op.setParentScope(global);
|
||||
op.put("prototypename", op, name);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error creating prototype: " + ignore);
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
|
||||
putPrototype(name, op);
|
||||
} else {
|
||||
// reset prototype to original state
|
||||
resetPrototype(op);
|
||||
|
||||
// set parent prototype just in case it has been changed
|
||||
op.setPrototype(opp);
|
||||
}
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a new prototyped hopobject and then calls
|
||||
// the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase(name) && !"root".equalsIgnoreCase(name)) {
|
||||
try {
|
||||
FunctionObject fp = new FunctionObject(name, HopObject.hopObjCtor, global);
|
||||
|
||||
fp.addAsConstructor(global, op);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error adding ctor for " + name + ": " + ignore);
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
for (Iterator it = prototype.getZippedCode().values().iterator(); it.hasNext();) {
|
||||
Object code = it.next();
|
||||
|
||||
evaluate(prototype, code);
|
||||
}
|
||||
|
||||
for (Iterator it = prototype.getCode().values().iterator(); it.hasNext();) {
|
||||
Object code = it.next();
|
||||
|
||||
evaluate(prototype, code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an object prototype to its initial state, removing all application specific
|
||||
* functions.
|
||||
*/
|
||||
synchronized void resetPrototype(Scriptable op) {
|
||||
Object[] ids = op.getIds();
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
/* String prop = en.nextElement ().toString ();
|
||||
try {
|
||||
ESValue esv = op.getProperty (prop, prop.hashCode ());
|
||||
if (esv instanceof ConstructedFunctionObject || esv instanceof FesiActionAdapter.ThrowException)
|
||||
op.deleteProperty (prop, prop.hashCode());
|
||||
} catch (Exception x) {} */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before an execution context is entered to let the
|
||||
* engine know it should update its prototype information.
|
||||
*/
|
||||
public synchronized void updatePrototypes() {
|
||||
if ((System.currentTimeMillis() - lastUpdate) < 1000L) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection protos = app.getPrototypes();
|
||||
|
||||
for (Iterator i = protos.iterator(); i.hasNext();) {
|
||||
Prototype proto = (Prototype) i.next();
|
||||
TypeInfo info = (TypeInfo) prototypes.get(proto.getName());
|
||||
|
||||
if (info == null) {
|
||||
// a prototype we don't know anything about yet. Init local update info.
|
||||
initPrototype(proto);
|
||||
info = (TypeInfo) prototypes.get(proto.getName());
|
||||
}
|
||||
|
||||
// only update prototype if it has already been initialized.
|
||||
// otherwise, this will be done on demand
|
||||
// System.err.println ("CHECKING PROTO "+proto+": "+info);
|
||||
if (info.lastUpdate > 0) {
|
||||
Prototype p = app.typemgr.getPrototype(info.protoName);
|
||||
|
||||
if (p != null) {
|
||||
// System.err.println ("UPDATING PROTO: "+p);
|
||||
app.typemgr.updatePrototype(p);
|
||||
|
||||
if (p.getLastUpdate() > info.lastUpdate) {
|
||||
evaluatePrototype(p);
|
||||
info.lastUpdate = p.getLastUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object has a function property (public method if it
|
||||
* is a java object) with that name.
|
||||
*/
|
||||
public boolean hasFunction(String protoname, String fname) {
|
||||
// System.err.println ("HAS_FUNC: "+fname);
|
||||
try {
|
||||
Scriptable op = getPrototype(protoname);
|
||||
|
||||
// if this is an untyped object return false
|
||||
if (op == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object func = ScriptableObject.getProperty(op, fname);
|
||||
|
||||
if ((func != null) && func instanceof Function) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception esx) {
|
||||
// System.err.println ("Error in hasFunction: "+esx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an input argument from Java to the scripting runtime
|
||||
* representation.
|
||||
*/
|
||||
|
||||
/* public static ESValue processXmlRpcArgument (Object what, Evaluator evaluator) throws Exception {
|
||||
if (what == null)
|
||||
return ESNull.theNull;
|
||||
if (what instanceof Vector) {
|
||||
Vector v = (Vector) what;
|
||||
ArrayPrototype retval = new ArrayPrototype (evaluator.getArrayPrototype (), evaluator);
|
||||
int l = v.size ();
|
||||
for (int i=0; i<l; i++)
|
||||
retval.putProperty (i, processXmlRpcArgument (v.elementAt (i), evaluator));
|
||||
return retval;
|
||||
}
|
||||
if (what instanceof Hashtable) {
|
||||
Hashtable t = (Hashtable) what;
|
||||
ESObject retval = new ObjectPrototype (evaluator.getObjectPrototype (), evaluator);
|
||||
for (Enumeration e=t.keys(); e.hasMoreElements(); ) {
|
||||
String next = (String) e.nextElement ();
|
||||
retval.putProperty (next, processXmlRpcArgument (t.get (next), evaluator), next.hashCode ());
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
if (what instanceof String)
|
||||
return new ESString (what.toString ());
|
||||
if (what instanceof Number)
|
||||
return new ESNumber (new Double (what.toString ()).doubleValue ());
|
||||
if (what instanceof Boolean)
|
||||
return ESBoolean.makeBoolean (((Boolean) what).booleanValue ());
|
||||
if (what instanceof Date)
|
||||
return new DatePrototype (evaluator, (Date) what);
|
||||
return ESLoader.normalizeValue (what, evaluator);
|
||||
} */
|
||||
|
||||
/**
|
||||
* convert a JavaScript Object object to a generic Java object stucture.
|
||||
*/
|
||||
|
||||
/* public static Object processXmlRpcResponse (ESValue what) throws EcmaScriptException {
|
||||
if (what == null || what instanceof ESNull)
|
||||
return null;
|
||||
if (what instanceof ArrayPrototype) {
|
||||
ArrayPrototype a = (ArrayPrototype) what;
|
||||
int l = a.size ();
|
||||
Vector v = new Vector ();
|
||||
for (int i=0; i<l; i++) {
|
||||
Object nj = processXmlRpcResponse (a.getProperty (i));
|
||||
v.addElement (nj);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (what instanceof ObjectPrototype) {
|
||||
ObjectPrototype o = (ObjectPrototype) what;
|
||||
Hashtable t = new Hashtable ();
|
||||
for (Enumeration e=o.getProperties (); e.hasMoreElements (); ) {
|
||||
String next = (String) e.nextElement ();
|
||||
// We don't do deep serialization of HopObjects to avoid
|
||||
// that the whole web site structure is sucked out with one
|
||||
// object. Instead we return some kind of "proxy" objects
|
||||
// that only contain the prototype and id of the HopObject property.
|
||||
Object nj = null;
|
||||
ESValue esv = o.getProperty (next, next.hashCode ());
|
||||
if (esv instanceof ESNode) {
|
||||
INode node = ((ESNode) esv).getNode ();
|
||||
if (node != null) {
|
||||
Hashtable nt = new Hashtable ();
|
||||
nt.put ("id", node.getID());
|
||||
if (node.getPrototype() != null)
|
||||
nt.put ("prototype", node.getPrototype ());
|
||||
nj = nt;
|
||||
}
|
||||
} else
|
||||
nj = processXmlRpcResponse (esv);
|
||||
if (nj != null) // can't put null as value in hashtable
|
||||
t.put (next, nj);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
if (what instanceof ESUndefined || what instanceof ESNull)
|
||||
return null;
|
||||
Object jval = what.toJavaObject ();
|
||||
if (jval instanceof Byte || jval instanceof Short)
|
||||
jval = new Integer (jval.toString ());
|
||||
return jval;
|
||||
} */
|
||||
|
||||
/**
|
||||
* Return the application we're running in
|
||||
*/
|
||||
public Application getApplication() {
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a raw prototype, i.e. in potentially unfinished state
|
||||
* without checking if it needs to be updated.
|
||||
*/
|
||||
private Scriptable getRawPrototype(String protoName) {
|
||||
if (protoName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInfo info = (TypeInfo) prototypes.get(protoName);
|
||||
|
||||
return (info == null) ? null : info.objectPrototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object prototype for a prototype name and initialize/update it
|
||||
* if necessary.
|
||||
*/
|
||||
public Scriptable getPrototype(String protoName) {
|
||||
if (protoName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInfo info = (TypeInfo) prototypes.get(protoName);
|
||||
|
||||
if ((info != null) && (info.lastUpdate == 0)) {
|
||||
Prototype p = app.typemgr.getPrototype(protoName);
|
||||
|
||||
if (p != null) {
|
||||
app.typemgr.updatePrototype(p);
|
||||
|
||||
if (p.getLastUpdate() > info.lastUpdate) {
|
||||
info.lastUpdate = p.getLastUpdate();
|
||||
evaluatePrototype(p);
|
||||
}
|
||||
|
||||
// set info.lastUpdate to 1 if it is 0 so we know we
|
||||
// have initialized this prototype already, even if
|
||||
// it is empty (i.e. doesn't contain any scripts/skins/actoins
|
||||
if (info.lastUpdate == 0) {
|
||||
info.lastUpdate = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (info == null) ? null : info.objectPrototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an object prototype for a certain prototype name.
|
||||
*/
|
||||
public void putPrototype(String protoName, Scriptable op) {
|
||||
if ((protoName != null) && (op != null)) {
|
||||
prototypes.put(protoName, new TypeInfo(op, protoName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param scope ...
|
||||
* @param obj ...
|
||||
* @param staticType ...
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public Object wrap(Scriptable scope, Object obj, Class staticType) {
|
||||
if (obj instanceof INode) {
|
||||
return getNodeWrapper((INode) obj);
|
||||
}
|
||||
|
||||
if (obj instanceof IPathElement) {
|
||||
return getElementWrapper(obj);
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
return new MapWrapper((Map) obj, this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Script wrapper for an object. In contrast to getElementWrapper, this is called for
|
||||
* any Java object, not just the ones in the request path which we know are scripted.
|
||||
* So what we do is check if the object belongs to a scripted class. If so, we call getElementWrapper()
|
||||
* with the object, otherwise we return a generic unscripted object wrapper.
|
||||
*/
|
||||
/* public Scriptable getObjectWrapper(Object e) {
|
||||
if (app.getPrototypeName(e) != null) {
|
||||
return getElementWrapper(e);
|
||||
}
|
||||
/ else if (e instanceof INode)
|
||||
return new ESNode ((INode) e, this); /
|
||||
else {
|
||||
return Context.getCurrentContext().toObject(e, global);
|
||||
}
|
||||
} */
|
||||
|
||||
/**
|
||||
* Get a Script wrapper for any given object. If the object implements the IPathElement
|
||||
* interface, the getPrototype method will be used to retrieve the name of the prototype
|
||||
* to use. Otherwise, a Java-Class-to-Script-Prototype mapping is consulted.
|
||||
*/
|
||||
public Scriptable getElementWrapper(Object e) {
|
||||
// Gotta find out the prototype name to use for this object...
|
||||
String prototypeName = app.getPrototypeName(e);
|
||||
|
||||
Scriptable op = getPrototype(prototypeName);
|
||||
|
||||
if (op == null) {
|
||||
op = getPrototype("hopobject");
|
||||
}
|
||||
|
||||
return new JavaObject(global, e, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a script wrapper for an instance of helma.objectmodel.INode
|
||||
*/
|
||||
public Scriptable getNodeWrapper(INode n) {
|
||||
// FIXME: should this return ESNull.theNull?
|
||||
if (n == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HopObject esn = (HopObject) wrappercache.get(n);
|
||||
|
||||
if (esn == null) {
|
||||
try {
|
||||
String protoname = n.getPrototype();
|
||||
|
||||
Scriptable op = null;
|
||||
|
||||
// set the DbMapping of the node according to its prototype.
|
||||
// this *should* be done on the objectmodel level, but isn't currently
|
||||
// for embedded nodes since there's not enough type info at the objectmodel level
|
||||
// for those nodes.
|
||||
if ((protoname != null) && (protoname.length() > 0) &&
|
||||
(n.getDbMapping() == null)) {
|
||||
n.setDbMapping(app.getDbMapping(protoname));
|
||||
}
|
||||
|
||||
op = getPrototype(protoname);
|
||||
|
||||
// no prototype found for this node?
|
||||
if (op == null) {
|
||||
op = getPrototype("hopobject");
|
||||
}
|
||||
|
||||
esn = new HopObject();
|
||||
esn.init(this, n);
|
||||
esn.setPrototype(op);
|
||||
|
||||
wrappercache.put(n, esn);
|
||||
|
||||
// app.logEvent ("Wrapper for "+n+" created");
|
||||
} catch (Exception x) {
|
||||
System.err.println("Error creating node wrapper: " + x);
|
||||
throw new RuntimeException(x.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return esn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new Node wrapper with the wrapper cache. This is used by the
|
||||
* Node constructor.
|
||||
*/
|
||||
public void putNodeWrapper(INode n, Scriptable esn) {
|
||||
wrappercache.put(n, esn);
|
||||
}
|
||||
|
||||
private synchronized void evaluate(Prototype prototype, Object code) {
|
||||
if (code instanceof FunctionFile) {
|
||||
FunctionFile funcfile = (FunctionFile) code;
|
||||
File file = funcfile.getFile();
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
FileReader fr = new FileReader(file);
|
||||
|
||||
updateEvaluator(prototype, fr, funcfile.getSourceName());
|
||||
} catch (IOException iox) {
|
||||
app.logEvent("Error updating function file: " + iox);
|
||||
}
|
||||
} else {
|
||||
StringReader reader = new StringReader(funcfile.getContent());
|
||||
|
||||
updateEvaluator(prototype, reader, funcfile.getSourceName());
|
||||
}
|
||||
} else if (code instanceof ActionFile) {
|
||||
ActionFile action = (ActionFile) code;
|
||||
RhinoActionAdapter fa = new RhinoActionAdapter(action);
|
||||
|
||||
try {
|
||||
updateEvaluator(prototype, new StringReader(fa.function),
|
||||
action.getSourceName());
|
||||
} catch (Exception esx) {
|
||||
app.logEvent("Error parsing " + action + ": " + esx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void updateEvaluator(Prototype prototype, Reader reader,
|
||||
String sourceName) {
|
||||
// context = Context.enter(context);
|
||||
try {
|
||||
Scriptable op = getPrototype(prototype.getName());
|
||||
|
||||
// get the current context
|
||||
Context cx = Context.getCurrentContext();
|
||||
|
||||
// do the update, evaluating the file
|
||||
cx.evaluateReader(op, reader, sourceName, 1, null);
|
||||
} catch (Throwable e) {
|
||||
app.logEvent("Error parsing function file " + sourceName + ": " + e);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TypeInfo {
|
||||
Scriptable objectPrototype;
|
||||
long lastUpdate = 0;
|
||||
String protoName;
|
||||
|
||||
public TypeInfo(Scriptable op, String name) {
|
||||
objectPrototype = op;
|
||||
protoName = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("TypeInfo[" + protoName + "," + new Date(lastUpdate) + "]");
|
||||
}
|
||||
}
|
||||
}
|
442
src/helma/scripting/rhino/RhinoEngine.java
Normal file
442
src/helma/scripting/rhino/RhinoEngine.java
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.extensions.ConfigurationException;
|
||||
import helma.extensions.HelmaExtension;
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.main.Server;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.Relation;
|
||||
import helma.scripting.*;
|
||||
import helma.scripting.fesi.extensions.*;
|
||||
import helma.util.CacheMap;
|
||||
import helma.util.Updatable;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This is the implementation of ScriptingEnvironment for the Mozilla Rhino EcmaScript interpreter.
|
||||
*/
|
||||
public final class RhinoEngine implements ScriptingEngine {
|
||||
static Map coreMap;
|
||||
|
||||
// the application we're running in
|
||||
public Application app;
|
||||
|
||||
// The Rhino context
|
||||
Context context;
|
||||
|
||||
// the global object
|
||||
Scriptable global;
|
||||
|
||||
// the request evaluator instance owning this fesi evaluator
|
||||
RequestEvaluator reval;
|
||||
RhinoCore core;
|
||||
|
||||
// remember global variables from last invokation to be able to
|
||||
// do lazy cleanup
|
||||
Map lastGlobals = null;
|
||||
|
||||
// the global vars set by extensions
|
||||
HashMap extensionGlobals;
|
||||
|
||||
/**
|
||||
* Zero argument constructor.
|
||||
*/
|
||||
public RhinoEngine() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the scripting engine with an application and a request evaluator
|
||||
*/
|
||||
public void init(Application app, RequestEvaluator reval) {
|
||||
this.app = app;
|
||||
this.reval = reval;
|
||||
core = getRhinoCore(app);
|
||||
context = Context.enter();
|
||||
context.setCompileFunctionsWithDynamicScope(true);
|
||||
|
||||
try {
|
||||
global = context.newObject(core.global);
|
||||
global.setPrototype(core.global);
|
||||
global.setParentScope(null);
|
||||
|
||||
// context.putThreadLocal ("reval", reval);
|
||||
// context.putThreadLocal ("engine", this);
|
||||
extensionGlobals = new HashMap();
|
||||
|
||||
Vector extVec = Server.getServer().getExtensions();
|
||||
|
||||
for (int i = 0; i < extVec.size(); i++) {
|
||||
HelmaExtension ext = (HelmaExtension) extVec.get(i);
|
||||
|
||||
try {
|
||||
HashMap tmpGlobals = ext.initScripting(app, this);
|
||||
|
||||
if (tmpGlobals != null) {
|
||||
extensionGlobals.putAll(tmpGlobals);
|
||||
}
|
||||
} catch (ConfigurationException e) {
|
||||
app.logEvent("Couldn't initialize extension " + ext.getName() + ": " +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// context.removeThreadLocal ("reval");
|
||||
// context.removeThreadLocal ("engine");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Cannot initialize interpreter");
|
||||
System.err.println("Error: " + e);
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} finally {
|
||||
// Context.exit ();
|
||||
}
|
||||
}
|
||||
|
||||
static synchronized RhinoCore getRhinoCore(Application app) {
|
||||
RhinoCore core = null;
|
||||
|
||||
if (coreMap == null) {
|
||||
coreMap = new HashMap();
|
||||
} else {
|
||||
core = (RhinoCore) coreMap.get(app);
|
||||
}
|
||||
|
||||
if (core == null) {
|
||||
core = new RhinoCore(app);
|
||||
coreMap.put(app, core);
|
||||
}
|
||||
|
||||
return core;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before an execution context is entered to let the
|
||||
* engine know it should update its prototype information.
|
||||
*/
|
||||
public void updatePrototypes() {
|
||||
context = Context.enter(context);
|
||||
context.setCompileFunctionsWithDynamicScope(true);
|
||||
context.setWrapHandler(core);
|
||||
|
||||
int optLevel = 0;
|
||||
|
||||
try {
|
||||
optLevel = Integer.parseInt(app.getProperty("rhino.optlevel"));
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
context.setOptimizationLevel(optLevel);
|
||||
core.updatePrototypes();
|
||||
context.putThreadLocal("reval", reval);
|
||||
context.putThreadLocal("engine", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when an execution context for a request
|
||||
* evaluation is entered. The globals parameter contains the global values
|
||||
* to be applied during this execution context.
|
||||
*/
|
||||
public void enterContext(HashMap globals) throws ScriptingException {
|
||||
// set the thread filed in the FESI evaluator
|
||||
// evaluator.thread = Thread.currentThread ();
|
||||
// set globals on the global object
|
||||
// context = Context.enter (context);
|
||||
globals.putAll(extensionGlobals);
|
||||
|
||||
if ((globals != null) && (globals != lastGlobals)) {
|
||||
// loop through global vars and set them
|
||||
for (Iterator i = globals.keySet().iterator(); i.hasNext();) {
|
||||
String k = (String) i.next();
|
||||
Object v = globals.get(k);
|
||||
Scriptable scriptable = null;
|
||||
|
||||
try {
|
||||
// we do a lot of extra work to make access to global variables
|
||||
// comfortable to EcmaScript coders, i.e. we use a lot of custom wrappers
|
||||
// that expose properties and functions in a special way instead of just going
|
||||
// with the standard java object wrappers.
|
||||
if ("path".equals(k)) {
|
||||
Scriptable arr = context.newObject(global, "Array");
|
||||
List path = (List) v;
|
||||
|
||||
// register path elements with their prototype
|
||||
for (int j = 0; j < path.size(); j++) {
|
||||
Object pathElem = path.get(j);
|
||||
Scriptable wrappedElement = context.toObject(pathElem, global);
|
||||
|
||||
arr.put(j, arr, wrappedElement);
|
||||
|
||||
String protoname = app.getPrototypeName(pathElem);
|
||||
|
||||
if (protoname != null) {
|
||||
arr.put(protoname, arr, wrappedElement);
|
||||
}
|
||||
}
|
||||
|
||||
v = arr;
|
||||
}
|
||||
|
||||
/* if (v instanceof Map) {
|
||||
sv = new ESMapWrapper (this, (Map) v);
|
||||
} else if ("path".equals (k)) {
|
||||
ArrayPrototype parr = new ArrayPrototype (evaluator.getArrayPrototype(), evaluator);
|
||||
List path = (List) v;
|
||||
// register path elements with their prototype
|
||||
for (int j=0; j<path.size(); j++) {
|
||||
Object pathElem = path.get (j);
|
||||
ESValue wrappedElement = getElementWrapper (pathElem);
|
||||
parr.putProperty (j, wrappedElement);
|
||||
String protoname = app.getPrototypeName (pathElem);
|
||||
if (protoname != null)
|
||||
parr.putHiddenProperty (protoname, wrappedElement);
|
||||
}
|
||||
sv = parr;
|
||||
} else if ("req".equals (k)) {
|
||||
sv = new ESBeanWrapper (new RequestBean ((RequestTrans) v), this);
|
||||
} else if ("res".equals (k)) {
|
||||
sv = new ESBeanWrapper (new ResponseBean ((ResponseTrans) v), this);
|
||||
} else if ("session".equals (k)) {
|
||||
sv = new ESBeanWrapper (new SessionBean ((Session)v), this);
|
||||
} else if ("app".equals (k)) {
|
||||
sv = new ESBeanWrapper (new ApplicationBean ((Application)v), this);
|
||||
} else if (v instanceof ESValue) {
|
||||
sv = (ESValue)v;
|
||||
} else {
|
||||
sv = ESLoader.normalizeValue (v, evaluator);
|
||||
} */
|
||||
scriptable = context.toObject(v, global);
|
||||
global.put(k, global, scriptable);
|
||||
} catch (Exception x) {
|
||||
app.logEvent("Error setting global variable " + k + ": " + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remember the globals set on this evaluator
|
||||
lastGlobals = globals;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to let the scripting engine know that the current
|
||||
* execution context has terminated.
|
||||
*/
|
||||
public void exitContext() {
|
||||
context.exit();
|
||||
context.removeThreadLocal("reval");
|
||||
context.removeThreadLocal("engine");
|
||||
|
||||
// unset the thread filed in the FESI evaluator
|
||||
// evaluator.thread = null;
|
||||
// loop through previous globals and unset them, if necessary.
|
||||
|
||||
/* if (lastGlobals != null) {
|
||||
for (Iterator i=lastGlobals.keySet().iterator(); i.hasNext(); ) {
|
||||
String g = (String) i.next ();
|
||||
try {
|
||||
global.deleteProperty (g, g.hashCode());
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Error resetting global property: "+g);
|
||||
}
|
||||
}
|
||||
lastGlobals = null;
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a function on some object, using the given arguments and global vars.
|
||||
*/
|
||||
public Object invoke(Object thisObject, String functionName, Object[] args,
|
||||
boolean xmlrpc) throws ScriptingException {
|
||||
Scriptable eso = null;
|
||||
|
||||
if (thisObject == null) {
|
||||
eso = global;
|
||||
} else {
|
||||
eso = context.toObject(thisObject, global);
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
// XML-RPC requires special argument conversion
|
||||
// if (xmlrpc)
|
||||
// esv[i] = processXmlRpcArgument (args[i], evaluator);
|
||||
// for java.util.Map objects, we use the special "tight" wrapper
|
||||
// that makes the Map look like a native object
|
||||
|
||||
/* else if (args[i] instanceof Map)
|
||||
esv[i] = new ESMapWrapper (this, (Map) args[i]);
|
||||
else
|
||||
esv[i] = ESLoader.normalizeValue (args[i], evaluator); */
|
||||
args[i] = context.toObject(args[i], global);
|
||||
}
|
||||
|
||||
Object f = ScriptableObject.getProperty(eso, functionName);
|
||||
|
||||
if ((f == ScriptableObject.NOT_FOUND) || !(f instanceof Function)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object retval = ((Function) f).call(context, global, eso, args);
|
||||
|
||||
// if (xmlrpc)
|
||||
// return processXmlRpcResponse (retval);
|
||||
if ((retval == null) || (retval == Undefined.instance)) {
|
||||
return null;
|
||||
} else if (retval instanceof NativeJavaObject) {
|
||||
return ((NativeJavaObject) retval).unwrap();
|
||||
} else {
|
||||
return retval;
|
||||
}
|
||||
} catch (RedirectException redirect) {
|
||||
throw redirect;
|
||||
} catch (TimeoutException timeout) {
|
||||
throw timeout;
|
||||
} catch (ConcurrencyException concur) {
|
||||
throw concur;
|
||||
} catch (Exception x) {
|
||||
// check if this is a redirect exception, which has been converted by fesi
|
||||
// into an EcmaScript exception, which is why we can't explicitly catch it
|
||||
if (reval.res.getRedirect() != null) {
|
||||
throw new RedirectException(reval.res.getRedirect());
|
||||
}
|
||||
|
||||
// do the same for not-modified responses
|
||||
if (reval.res.getNotModified()) {
|
||||
throw new RedirectException(null);
|
||||
}
|
||||
|
||||
// has the request timed out? If so, throw TimeoutException
|
||||
// if (evaluator.thread != Thread.currentThread())
|
||||
// throw new TimeoutException ();
|
||||
// create and throw a ScriptingException with the right message
|
||||
String msg = x.toString();
|
||||
|
||||
if (app.debug()) {
|
||||
System.err.println("Error in Script: " + msg);
|
||||
x.printStackTrace();
|
||||
}
|
||||
|
||||
throw new ScriptingException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the evaluator know that the current evaluation has been
|
||||
* aborted. This is done by setting the thread ref in the evaluator
|
||||
* object to null.
|
||||
*/
|
||||
public void abort() {
|
||||
// unset the thread filed in the FESI evaluator
|
||||
// evaluator.thread = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object has a function property (public method if it
|
||||
* is a java object) with that name.
|
||||
*/
|
||||
public boolean hasFunction(Object obj, String fname) {
|
||||
// System.err.println ("HAS_FUNC: "+fname);
|
||||
return core.hasFunction(app.getPrototypeName(obj), fname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object has a defined property (public field if it
|
||||
* is a java object) with that name.
|
||||
*/
|
||||
public Object get(Object obj, String propname) {
|
||||
if ((obj == null) || (propname == null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String prototypeName = app.getPrototypeName(obj);
|
||||
|
||||
if ("user".equalsIgnoreCase(prototypeName) &&
|
||||
"password".equalsIgnoreCase(propname)) {
|
||||
return "[macro access to password property not allowed]";
|
||||
}
|
||||
|
||||
// if this is a HopObject, check if the property is defined
|
||||
// in the type.properties db-mapping.
|
||||
if (obj instanceof INode) {
|
||||
DbMapping dbm = app.getDbMapping(prototypeName);
|
||||
|
||||
if (dbm != null) {
|
||||
Relation rel = dbm.propertyToRelation(propname);
|
||||
|
||||
if ((rel == null) || !rel.isPrimitive()) {
|
||||
return "[property \"" + propname + "\" is not defined for " +
|
||||
prototypeName + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scriptable so = context.toObject(obj, global);
|
||||
|
||||
try {
|
||||
Object prop = so.get(propname, so);
|
||||
|
||||
if (prop != Undefined.instance) {
|
||||
return prop;
|
||||
}
|
||||
} catch (Exception esx) {
|
||||
// System.err.println ("Error in getProperty: "+esx);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an introspector to this engine. FIXME: not yet implemented for the rhino engine.
|
||||
*/
|
||||
public IPathElement getIntrospector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the application we're running in
|
||||
*/
|
||||
public Application getApplication() {
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RequestEvaluator owning and driving this FESI evaluator.
|
||||
*/
|
||||
public RequestEvaluator getRequestEvaluator() {
|
||||
return reval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Response object of the current evaluation context. Proxy method to RequestEvaluator.
|
||||
*/
|
||||
public ResponseTrans getResponse() {
|
||||
return reval.res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Request object of the current evaluation context. Proxy method to RequestEvaluator.
|
||||
*/
|
||||
public RequestTrans getRequest() {
|
||||
return reval.req;
|
||||
}
|
||||
}
|
274
src/helma/scripting/rhino/XmlObject.java
Normal file
274
src/helma/scripting/rhino/XmlObject.java
Normal file
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import helma.framework.core.Application;
|
||||
import helma.framework.core.RequestEvaluator;
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.db.Node;
|
||||
import helma.objectmodel.dom.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class XmlObject {
|
||||
RhinoCore core;
|
||||
|
||||
/**
|
||||
* Creates a new XmlObject object.
|
||||
*
|
||||
* @param core ...
|
||||
*/
|
||||
public XmlObject(RhinoCore core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param hopObject ...
|
||||
* @param file ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws IOException ...
|
||||
* @throws RuntimeException ...
|
||||
*/
|
||||
public boolean write(Object hopObject, String file)
|
||||
throws IOException {
|
||||
INode node = null;
|
||||
|
||||
if (hopObject instanceof HopObject) {
|
||||
node = ((HopObject) hopObject).node;
|
||||
}
|
||||
|
||||
// we definitly need a node
|
||||
if (node == null) {
|
||||
throw new RuntimeException("First argument in Xml.write() is not an hopobject");
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
throw new RuntimeException("Second argument file name must not be null");
|
||||
}
|
||||
|
||||
File tmpFile = new File(file + ".tmp." + XmlWriter.generateID());
|
||||
XmlWriter writer = new XmlWriter(tmpFile, "UTF-8");
|
||||
|
||||
writer.setDatabaseMode(false);
|
||||
|
||||
boolean result = writer.write(node);
|
||||
|
||||
writer.close();
|
||||
|
||||
File finalFile = new File(file);
|
||||
|
||||
tmpFile.renameTo(finalFile);
|
||||
core.getApplication().logEvent("wrote xml to " + finalFile.getAbsolutePath());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Xml.create() is used to get a string containing the xml-content.
|
||||
* Useful if Xml-content should be made public through the web.
|
||||
*/
|
||||
public String writeToString(Object hopObject) throws IOException {
|
||||
INode node = null;
|
||||
|
||||
if (hopObject instanceof HopObject) {
|
||||
node = ((HopObject) hopObject).node;
|
||||
}
|
||||
|
||||
// we definitly need a node
|
||||
if (node == null) {
|
||||
throw new RuntimeException("First argument in Xml.write() is not an hopobject");
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
XmlWriter writer = new XmlWriter(out, "UTF-8");
|
||||
|
||||
// in case we ever want to limit serialization depth...
|
||||
// if (arguments.length > 1 && arguments[1] instanceof ESNumber)
|
||||
// writer.setMaxLevels(arguments[1].toInt32());
|
||||
writer.setDatabaseMode(false);
|
||||
|
||||
boolean result = writer.write(node);
|
||||
|
||||
writer.flush();
|
||||
|
||||
return out.toString("UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param file ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws RuntimeException ...
|
||||
*/
|
||||
public Object read(String file) throws RuntimeException {
|
||||
return read(file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param file ...
|
||||
* @param hopObject ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws RuntimeException ...
|
||||
*/
|
||||
public Object read(String file, Object hopObject) throws RuntimeException {
|
||||
if (file == null) {
|
||||
throw new RuntimeException("Missing arguments in Xml.read()");
|
||||
}
|
||||
|
||||
INode node = null;
|
||||
|
||||
if (hopObject instanceof HopObject) {
|
||||
node = ((HopObject) hopObject).node;
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
// make sure we have a node, even if 2nd arg doesn't exist or is not a node
|
||||
node = new Node((String) null, (String) null,
|
||||
core.getApplication().getWrappedNodeManager());
|
||||
}
|
||||
|
||||
try {
|
||||
XmlReader reader = new XmlReader();
|
||||
INode result = reader.read(new File(file), node);
|
||||
|
||||
return core.getNodeWrapper(result);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new RuntimeException("Can't load XML parser:" + e);
|
||||
} catch (Exception f) {
|
||||
throw new RuntimeException(f.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws RuntimeException ...
|
||||
*/
|
||||
public Object readFromString(String str) throws RuntimeException {
|
||||
return readFromString(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param str ...
|
||||
* @param hopObject ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws RuntimeException ...
|
||||
*/
|
||||
public Object readFromString(String str, Object hopObject)
|
||||
throws RuntimeException {
|
||||
if (str == null) {
|
||||
throw new RuntimeException("Missing arguments in Xml.read()");
|
||||
}
|
||||
|
||||
INode node = null;
|
||||
|
||||
if (hopObject instanceof HopObject) {
|
||||
node = ((HopObject) hopObject).node;
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
// make sure we have a node, even if 2nd arg doesn't exist or is not a node
|
||||
node = new Node((String) null, (String) null,
|
||||
core.getApplication().getWrappedNodeManager());
|
||||
}
|
||||
|
||||
try {
|
||||
XmlReader reader = new XmlReader();
|
||||
INode result = reader.read(new StringReader(str), node);
|
||||
|
||||
return core.getNodeWrapper(result);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new RuntimeException("Can't load XML parser:" + e);
|
||||
} catch (Exception f) {
|
||||
throw new RuntimeException(f.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/* class XmlGet extends BuiltinFunctionObject {
|
||||
XmlGet(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super(fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if ( arguments==null || arguments.length==0 )
|
||||
throw new EcmaScriptException("Xml.get() needs a location as an argument");
|
||||
try {
|
||||
XmlConverter converter;
|
||||
if ( arguments.length>1 ) {
|
||||
converter = new XmlConverter (arguments[1].toString());
|
||||
} else {
|
||||
converter = new XmlConverter ();
|
||||
}
|
||||
INode node = new helma.objectmodel.db.Node ( (String)null, (String)null, this.evaluator.engine.getApplication().getWrappedNodeManager() );
|
||||
INode result = converter.convert (arguments[0].toString(),node);
|
||||
return this.evaluator.engine.getNodeWrapper(result);
|
||||
} catch ( NoClassDefFoundError e ) {
|
||||
throw new EcmaScriptException("Can't load dom-capable xml parser.");
|
||||
} catch ( RuntimeException f ) {
|
||||
throw new EcmaScriptException(f.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
class XmlGetFromString extends BuiltinFunctionObject {
|
||||
XmlGetFromString(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super(fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if ( arguments==null || arguments.length==0 )
|
||||
throw new EcmaScriptException("Xml.getFromString() needs an XML string as parameter");
|
||||
try {
|
||||
XmlConverter converter;
|
||||
if ( arguments.length>1 ) {
|
||||
converter = new XmlConverter (arguments[1].toString());
|
||||
} else {
|
||||
converter = new XmlConverter ();
|
||||
}
|
||||
INode node = new helma.objectmodel.db.Node ( (String)null, (String)null, this.evaluator.engine.getApplication().getWrappedNodeManager() );
|
||||
INode result = converter.convertFromString (arguments[0].toString(),node);
|
||||
return this.evaluator.engine.getNodeWrapper(result);
|
||||
} catch ( NoClassDefFoundError e ) {
|
||||
throw new EcmaScriptException("Can't load dom-capable xml parser.");
|
||||
} catch ( RuntimeException f ) {
|
||||
throw new EcmaScriptException(f.toString());
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
Loading…
Add table
Reference in a new issue