merged changes from refactor_scripting_05_02 branch

This commit is contained in:
hns 2002-05-13 17:38:00 +00:00
parent 5a015fbbc5
commit 1bd0fe6c05
22 changed files with 1419 additions and 1438 deletions

View file

@ -3,14 +3,13 @@
package helma.framework; package helma.framework;
import FESI.Exceptions.EcmaScriptException;
/** /**
* RedirectException is thrown internally when a response is redirected to a * RedirectException is thrown internally when a response is redirected to a
* new URL. * new URL.
*/ */
public class RedirectException extends EcmaScriptException { public class RedirectException extends RuntimeException {
String url; String url;

View file

@ -35,8 +35,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
protected NodeManager nmgr; protected NodeManager nmgr;
// the class name of the scripting environment implementation // the class name of the scripting environment implementation
static final String scriptEnvironmentName = "helma.scripting.fesi.Environment"; ScriptingEnvironment scriptingEngine;
ScriptingEnvironment scriptEnv;
// the root of the website, if a custom root object is defined. // the root of the website, if a custom root object is defined.
// otherwise this is managed by the NodeManager and not cached here. // otherwise this is managed by the NodeManager and not cached here.
@ -49,6 +48,11 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
*/ */
public TypeManager typemgr; public TypeManager typemgr;
/**
* The skin manager for this application
*/
protected SkinManager skinmgr;
/** /**
* Each application has one internal request evaluator for calling * Each application has one internal request evaluator for calling
* the scheduler and other internal functions. * the scheduler and other internal functions.
@ -227,7 +231,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
/** /**
* Get the application ready to run, initializing the evaluators and type manager. * Get the application ready to run, initializing the evaluators and type manager.
*/ */
public void init () throws DbException { public void init () throws DbException, ScriptingException {
scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment ();
scriptingEngine.init (this, props);
eval = new RequestEvaluator (this); eval = new RequestEvaluator (this);
logEvent ("Starting evaluators for "+name); logEvent ("Starting evaluators for "+name);
@ -249,6 +255,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
typemgr.createPrototypes (); typemgr.createPrototypes ();
// logEvent ("Started type manager for "+name); // logEvent ("Started type manager for "+name);
skinmgr = new SkinManager (this);
rootMapping = getDbMapping ("root"); rootMapping = getDbMapping ("root");
userMapping = getDbMapping ("user"); userMapping = getDbMapping ("user");
SystemProperties p = new SystemProperties (); SystemProperties p = new SystemProperties ();
@ -366,7 +374,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
try { try {
RequestEvaluator re = (RequestEvaluator) freeThreads.pop (); RequestEvaluator re = (RequestEvaluator) freeThreads.pop ();
allThreads.removeElement (re); allThreads.removeElement (re);
typemgr.unregisterRequestEvaluator (re); // typemgr.unregisterRequestEvaluator (re);
re.stopThread (); re.stopThread ();
} catch (EmptyStackException empty) { } catch (EmptyStackException empty) {
return false; return false;
@ -520,6 +528,13 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
return nmgr.safe; return nmgr.safe;
} }
/**
* Return a transient node that is shared by all evaluators of this application ("app node")
*/
public INode getAppNode () {
return appnode;
}
/** /**
* Returns a Node representing a registered user of this application by his or her user name. * Returns a Node representing a registered user of this application by his or her user name.
@ -552,9 +567,16 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
* Return a collection containing all prototypes defined for this application * Return a collection containing all prototypes defined for this application
*/ */
public Collection getPrototypes () { public Collection getPrototypes () {
return typemgr.prototypes.values (); return typemgr.prototypes.values ();
} }
/**
* Retrurn a skin for a given object. The skin is found by determining the prototype
* to use for the object, then looking up the skin for the prototype.
*/
public Skin getSkin (Object object, String skinname, Object[] skinpath) {
return skinmgr.getSkin (object, skinname, skinpath); // not yet implemented
}
/** /**
* Return the user currently associated with a given Hop session ID. This may be * Return the user currently associated with a given Hop session ID. This may be
@ -815,6 +837,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
* within the Helma scripting and rendering framework. * within the Helma scripting and rendering framework.
*/ */
public String getPrototypeName (Object obj) { public String getPrototypeName (Object obj) {
if (obj == null)
return "global";
// check if e implements the IPathElement interface // check if e implements the IPathElement interface
if (obj instanceof IPathElement) if (obj instanceof IPathElement)
// e implements the getPrototype() method // e implements the getPrototype() method
@ -902,6 +926,14 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
} }
/**
* Get scripting environment for this application
*/
public ScriptingEnvironment getScriptingEnvironment () {
return scriptingEngine;
}
/** /**
* The run method performs periodic tasks like executing the scheduler method and * The run method performs periodic tasks like executing the scheduler method and
* kicking out expired user sessions. * kicking out expired user sessions.
@ -917,7 +949,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
try { try {
eval.invokeFunction ((INode) null, "onStart", new Object[0]); eval.invokeFunction ((INode) null, "onStart", new Object[0]);
} catch (Exception ignore) {} } catch (Exception ignore) {
System.err.println ("Error in "+name+"/onStart(): "+ignore);
}
while (Thread.currentThread () == worker) { while (Thread.currentThread () == worker) {
// get session timeout // get session timeout
@ -1022,7 +1056,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
* Check whether a prototype is for scripting a java class, i.e. if there's an entry * Check whether a prototype is for scripting a java class, i.e. if there's an entry
* for it in the class.properties file. * for it in the class.properties file.
*/ */
protected boolean isJavaPrototype (String typename) { public boolean isJavaPrototype (String typename) {
for (Enumeration en = classMapping.elements(); en.hasMoreElements(); ) { for (Enumeration en = classMapping.elements(); en.hasMoreElements(); ) {
String value = (String) en.nextElement (); String value = (String) en.nextElement ();
if (typename.equals (value)) if (typename.equals (value))
@ -1129,7 +1163,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
* *
*/ */
public int countMaxActiveEvaluators () { public int countMaxActiveEvaluators () {
return typemgr.countRegisteredRequestEvaluators () -1; // return typemgr.countRegisteredRequestEvaluators () -1;
// not available due to framework refactoring
return -1;
} }
/** /**
@ -1194,7 +1230,7 @@ class XmlRpcInvoker implements XmlRpcHandler {
RequestEvaluator ev = null; RequestEvaluator ev = null;
try { try {
ev = app.getEvaluator (); ev = app.getEvaluator ();
retval = ev.invokeXmlRpc (method, argvec); retval = ev.invokeXmlRpc (method, argvec.toArray());
} finally { } finally {
app.releaseEvaluator (ev); app.releaseEvaluator (ev);
} }

View file

@ -8,11 +8,8 @@ import java.util.Iterator;
import java.io.*; import java.io.*;
import helma.framework.*; import helma.framework.*;
import helma.scripting.*; import helma.scripting.*;
import helma.scripting.fesi.*;
import helma.objectmodel.*; import helma.objectmodel.*;
import helma.util.Updatable; import helma.util.Updatable;
import FESI.Data.*;
import FESI.Exceptions.EcmaScriptException;
/** /**
@ -66,7 +63,7 @@ public class Prototype {
// if parent has changed, update ES-prototypes in request evaluators // if parent has changed, update ES-prototypes in request evaluators
if (parent != old) { if (parent != old) {
Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); /* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) { while (evals.hasNext ()) {
try { try {
RequestEvaluator reval = (RequestEvaluator) evals.next (); RequestEvaluator reval = (RequestEvaluator) evals.next ();
@ -81,7 +78,7 @@ public class Prototype {
op.setPrototype (opp); op.setPrototype (opp);
} catch (Exception ignore) { } catch (Exception ignore) {
} }
} } */
} }
} }
@ -97,8 +94,8 @@ public class Prototype {
return (FunctionFile) functions.get (ffname); return (FunctionFile) functions.get (ffname);
} }
public Action getAction (String afname) { public ActionFile getActionFile (String afname) {
return (Action) actions.get (afname); return (ActionFile) actions.get (afname);
} }
public SkinFile getSkinFile (String sfname) { public SkinFile getSkinFile (String sfname) {
@ -131,71 +128,6 @@ public class Prototype {
} }
public void initRequestEvaluator (RequestEvaluator reval) {
// see if we already registered with this evaluator
if (reval.getPrototype (name) != null)
return;
ObjectPrototype op = null;
// get the prototype's prototype if possible and necessary
ObjectPrototype opp = null;
if (parent != null) {
// see if parent prototype is already registered. if not, register it
opp = reval.getPrototype (parent.getName ());
if (opp == null) {
parent.initRequestEvaluator (reval);
opp = reval.getPrototype (parent.getName ());
}
}
if (!"global".equalsIgnoreCase (name) && !"hopobject".equalsIgnoreCase (name) && opp == null) {
if (isJavaPrototype)
opp = reval.esObjectPrototype;
else
opp = reval.esNodePrototype;
}
if ("user".equalsIgnoreCase (name)) {
op = reval.esUserPrototype;
op.setPrototype (opp);
} else if ("global".equalsIgnoreCase (name))
op = reval.global;
else if ("hopobject".equalsIgnoreCase (name))
op = reval.esNodePrototype;
else {
op = new ObjectPrototype (opp, reval.evaluator);
try {
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
} catch (EcmaScriptException ignore) {}
}
reval.putPrototype (name, op);
// Register a constructor for all types except global.
// This will first create a node and then call the actual (scripted) constructor on it.
if (!"global".equalsIgnoreCase (name)) {
try {
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = functions.values().iterator(); it.hasNext(); ) {
FunctionFile ff = (FunctionFile) it.next ();
ff.updateRequestEvaluator (reval);
}
for (Iterator it = templates.values().iterator(); it.hasNext(); ) {
Template tmp = (Template) it.next ();
try {
tmp.updateRequestEvaluator (reval);
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = actions.values().iterator(); it.hasNext(); ) {
Action act = (Action) it.next ();
try {
act.updateRequestEvaluator (reval);
} catch (EcmaScriptException ignore) {}
}
}
public String toString () { public String toString () {

File diff suppressed because it is too large Load diff

View file

@ -278,9 +278,9 @@ public class Skin {
if (handlerObject == null) { if (handlerObject == null) {
// eiter because thisObject == null or the right object wasn't found in the object's parent path // eiter because thisObject == null or the right object wasn't found in the object's parent path
// go check request path for an object with matching prototype // go check request path for an object with matching prototype
int l = reval.reqPath.size(); int l = reval.requestPath.size();
for (int i=l-1; i>=0; i--) { for (int i=l-1; i>=0; i--) {
Object pathelem = reval.reqPath.getProperty (i).toJavaObject (); Object pathelem = reval.requestPath.get (i);
if (handler.equalsIgnoreCase (app.getPrototypeName (pathelem))) { if (handler.equalsIgnoreCase (app.getPrototypeName (pathelem))) {
handlerObject = pathelem; handlerObject = pathelem;
break; break;
@ -302,12 +302,12 @@ public class Skin {
// if so, the macro evaluates to the function. Otherwise, // if so, the macro evaluates to the function. Otherwise,
// a property/field with the name is used, if defined. // a property/field with the name is used, if defined.
Object v = null; Object v = null;
if (reval.hasFunction (handlerObject, name+"_macro")) { if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) {
// System.err.println ("Getting macro from function"); // System.err.println ("Getting macro from function");
v = reval.invokeDirectFunction (handlerObject, name+"_macro", arguments); v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval);
} else { } else {
// System.err.println ("Getting macro from property"); // System.err.println ("Getting macro from property");
v = reval.getProperty (handlerObject, name); v = app.scriptingEngine.get (handlerObject, name, reval);
} }
if (v != null) if (v != null)
writeToResponse (v.toString (), reval.res); writeToResponse (v.toString (), reval.res);

View file

@ -0,0 +1,134 @@
// SkinManager.java
// Copyright (c) Hannes Wallnöfer 2002
package helma.framework.core;
import java.util.HashMap;
import java.util.Iterator;
import helma.objectmodel.INode;
import java.io.*;
/**
* Manages skins for a Helma application
*/
public class SkinManager {
Application app;
public SkinManager (Application app) {
this.app = app;
}
public Skin getSkin (Object object, String skinname, Object[] skinpath) {
Prototype proto = app.getPrototype (object);
return getSkin (proto, skinname, "skin", skinpath);
}
public Skin getSkin (Prototype proto, String skinname, String extension, Object[] skinpath) {
if (proto == null)
return null;
Skin skin = null;
// First check if the skin has been already used within the execution of this request
/* SkinKey key = new SkinKey (proto.getName(), skinname, extension);
Skin skin = (Skin) skincache.get (key);
if (skin != null) {
return skin;
} */
// check for skinsets set via res.skinpath property
do {
if (skinpath != null) {
for (int i=0; i<skinpath.length; i++) {
skin = getSkinInternal (skinpath[i], proto.getName (), skinname, extension);
if (skin != null) {
// skincache.put (key, skin);
return skin;
}
}
}
// skin for this prototype wasn't found in the skinsets.
// the next step is to look if it is defined as skin file in the application directory
skin = proto.getSkin (skinname);
if (skin != null) {
// skincache.put (key, skin);
return skin;
}
// still not found. See if there is a parent prototype which might define the skin.
proto = proto.getParentPrototype ();
} while (proto != null);
// looked every where, nothing to be found
return null;
}
protected Skin getSkinInternal (Object skinset, String prototype, String skinname, String extension) {
if (prototype == null || skinset == null)
return null;
// check if the skinset object is a HopObject (db based skin)
// or a String (file based skin)
if (skinset instanceof INode) {
INode n = ((INode) skinset).getNode (prototype, false);
if (n != null) {
n = n.getNode (skinname, false);
if (n != null) {
String skin = n.getString (extension, false);
if (skin != null) {
Skin s = (Skin) app.skincache.get (skin);
if (s == null) {
s = new Skin (skin, app);
app.skincache.put (skin, s);
}
return s;
}
}
}
} else {
// Skinset is interpreted as directory name from which to
// retrieve the skin
File f = new File (skinset.toString (), prototype);
f = new File (f, skinname+"."+extension);
if (f.exists() && f.canRead()) {
SkinFile sf = new SkinFile (f, skinname, app);
Skin s = sf.getSkin ();
return s;
}
}
// Inheritance is taken care of in the above getSkin method.
// the sequence is prototype.skin-from-db, prototype.skin-from-file, parent.from-db, parent.from-file etc.
return null;
}
/**
* Utility class to use for caching skins in a Hashtable.
* The key consists out of two strings: prototype name and skin name.
*/
final class SkinKey {
final String first, second, third;
public SkinKey (String first, String second, String third) {
this.first = first;
this.second = second;
this.third = third;
}
public boolean equals (Object other) {
try {
SkinKey key = (SkinKey) other;
return first.equals (key.first) && second.equals (key.second) && third.equals (key.third);
} catch (Exception x) {
return false;
}
}
public int hashCode () {
return first.hashCode () + second.hashCode () + third.hashCode ();
}
}
}

View file

@ -225,7 +225,7 @@ public class TypeManager {
} else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) { } else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
try { try {
Action af = new Action (tmpfile, tmpname, proto); ActionFile af = new ActionFile (tmpfile, tmpname, proto);
updatables.put (list[i], af); updatables.put (list[i], af);
nact.put (tmpname, af); nact.put (tmpname, af);
} catch (Throwable x) { } catch (Throwable x) {
@ -257,11 +257,12 @@ public class TypeManager {
proto.updatables = updatables; proto.updatables = updatables;
// init prototype on evaluators that are already initialized. // init prototype on evaluators that are already initialized.
Iterator evals = getRegisteredRequestEvaluators (); /* Iterator evals = getRegisteredRequestEvaluators ();
while (evals.hasNext ()) { while (evals.hasNext ()) {
RequestEvaluator reval = (RequestEvaluator) evals.next (); RequestEvaluator reval = (RequestEvaluator) evals.next ();
proto.initRequestEvaluator (reval); proto.initRequestEvaluator (reval);
} }*/
app.scriptingEngine.updatePrototype (proto);
} }
@ -347,7 +348,7 @@ public class TypeManager {
} else if (list[i].endsWith (app.actionExtension)) { } else if (list[i].endsWith (app.actionExtension)) {
try { try {
Action af = new Action (tmpfile, tmpname, proto); ActionFile af = new ActionFile (tmpfile, tmpname, proto);
proto.updatables.put (list[i], af); proto.updatables.put (list[i], af);
proto.actions.put (tmpname, af); proto.actions.put (tmpname, af);
} catch (Throwable x) { } catch (Throwable x) {
@ -362,29 +363,29 @@ public class TypeManager {
} }
// next go through existing updatables // next go through existing updatables
if (updatables == null) if (updatables != null) {
return; for (Iterator i = updatables.iterator(); i.hasNext(); ) {
for (Iterator i = updatables.iterator(); i.hasNext(); ) { Updatable upd = (Updatable) i.next();
Updatable upd = (Updatable) i.next();
if (upd.needsUpdate ()) { if (upd.needsUpdate ()) {
if (upd instanceof DbMapping) if (upd instanceof DbMapping)
rewire = true; rewire = true;
try { try {
upd.update (); upd.update ();
} catch (Exception x) { } catch (Exception x) {
if (upd instanceof DbMapping) if (upd instanceof DbMapping)
app.logEvent ("Error updating db mapping for type "+name+": "+x); app.logEvent ("Error updating db mapping for type "+name+": "+x);
else else
app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x); app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
}
} }
} }
} }
app.scriptingEngine.updatePrototype (proto);
} }
/*public void initRequestEvaluator (RequestEvaluator reval) {
public void initRequestEvaluator (RequestEvaluator reval) {
if (!registeredEvaluators.contains (reval)) if (!registeredEvaluators.contains (reval))
registeredEvaluators.add (reval); registeredEvaluators.add (reval);
for (Iterator it = prototypes.values().iterator(); it.hasNext(); ) { for (Iterator it = prototypes.values().iterator(); it.hasNext(); ) {
@ -404,7 +405,7 @@ public class TypeManager {
public int countRegisteredRequestEvaluators () { public int countRegisteredRequestEvaluators () {
return registeredEvaluators.size (); return registeredEvaluators.size ();
} } */
} }

View file

@ -72,16 +72,14 @@ public class ZippedAppFile implements Updatable {
String name = fname.substring (0, fname.lastIndexOf (".")); String name = fname.substring (0, fname.lastIndexOf ("."));
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
Action act = new Action (null, name, proto); ActionFile act = new ActionFile (content, name, proto);
act.update (content);
proto.actions.put (name, act); proto.actions.put (name, act);
} }
else if (fname.endsWith (".hsp")) { else if (fname.endsWith (".hsp")) {
String name = fname.substring (0, fname.lastIndexOf (".")); String name = fname.substring (0, fname.lastIndexOf ("."));
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
Template tmp = new Template (null, name, proto); Template tmp = new Template (content, name, proto);
tmp.update (content);
proto.templates.put (name, tmp); proto.templates.put (name, tmp);
} }
else if (fname.endsWith (".skin")) { else if (fname.endsWith (".skin")) {

View file

@ -0,0 +1,128 @@
// ActionFile.java
// Copyright (c) Helma.org 1998-2002
package 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 ActionFile is a file containing function code that is exposed as a URI
* of objects of this class/type. It is
* usually represented by a file with extension .hac (hop action file)
* that contains the raw body of the function.
*/
public class ActionFile implements Updatable {
String name;
String functionName;
Prototype prototype;
Application app;
File file;
String content;
long lastmod;
public ActionFile (File file, String name, Prototype proto) {
this.prototype = proto;
this.app = proto.getApplication ();
this.name = name;
functionName = getName()+"_action";
this.file = file;
this.content = null;
if (file != null)
update ();
}
public ActionFile (String content, String name, Prototype proto) {
this.prototype = proto;
this.app = proto.getApplication ();
this.name = name;
functionName = getName()+"_action";
this.file = null;
this.content = content;
}
/**
* Abstract method that must be implemented by subclasses to update evaluators with
* new content of action file.
*/
// protected abstract void update (String content) throws Exception;
/**
* Abstract method that must be implemented by subclasses to remove
* action from evaluators.
*/
// protected abstract void remove ();
/**
* Tell the type manager whether we need an update. this is the case when
* the file has been modified or deleted.
*/
public boolean needsUpdate () {
return lastmod != file.lastModified ();
}
public void update () {
if (!file.exists ()) {
// remove functions declared by this from all object prototypes
remove ();
} else {
try {
FileReader reader = new FileReader (file);
char cbuf[] = new char[(int) file.length ()];
reader.read (cbuf);
reader.close ();
content = new String (cbuf);
// update (content);
} catch (Exception filex) {
app.logEvent ("*** Error reading action file "+file+": "+filex);
}
lastmod = file.lastModified ();
}
}
protected void remove () {
prototype.actions.remove (name);
if (file != null)
prototype.updatables.remove (file.getName());
}
public String getName () {
return name;
}
public String getContent () {
return content;
}
public String getFunctionName () {
return functionName;
}
public Prototype getPrototype () {
return prototype;
}
public Application getApplication () {
return app;
}
public String toString () {
return "ActionFile["+prototype.getName()+"/"+functionName+"]";
}
}

View file

@ -11,13 +11,10 @@ import java.io.*;
import helma.framework.*; import helma.framework.*;
import helma.framework.core.*; import helma.framework.core.*;
import helma.util.Updatable; import helma.util.Updatable;
import FESI.Data.*;
import FESI.Exceptions.EcmaScriptException;
import FESI.Interpreter.*;
/** /**
* This represents a File containing JavaScript functions for a given Object. * This represents a File containing script functions for a given class/prototype.
*/ */
@ -44,8 +41,8 @@ public class FunctionFile implements Updatable {
} }
/** /**
* Create a function file without a file, passing the code directly. This is used for * Create a function file without a file, passing the code directly. This is used for
* files contained in zipped applications. The whole update mechanism is bypassed * files contained in zipped applications. The whole update mechanism is bypassed
* by immediately parsing the code. * by immediately parsing the code.
*/ */
public FunctionFile (String body, String name, Prototype proto) { public FunctionFile (String body, String name, Prototype proto) {
@ -54,20 +51,7 @@ public class FunctionFile implements Updatable {
this.name = name; this.name = name;
this.file = null; this.file = null;
this.content = body; this.content = body;
update ();
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) {
try {
StringEvaluationSource es = new StringEvaluationSource (body, null);
StringReader reader = new StringReader (body);
RequestEvaluator reval = (RequestEvaluator) evals.next ();
updateRequestEvaluator (reval, reader, es);
} catch (Exception ignore) {}
}
} }
/** /**
@ -75,108 +59,41 @@ public class FunctionFile implements Updatable {
* the file has been modified or deleted. * the file has been modified or deleted.
*/ */
public boolean needsUpdate () { public boolean needsUpdate () {
return lastmod != file.lastModified (); return file != null && lastmod != file.lastModified ();
} }
public void update () { public void update () {
if (!file.exists ()) {
remove ();
} else {
lastmod = file.lastModified ();
// app.typemgr.readFunctionFile (file, prototype.getName ());
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) {
try {
RequestEvaluator reval = (RequestEvaluator) evals.next ();
FileReader fr = new FileReader(file);
EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
updateRequestEvaluator (reval, fr, es);
} catch (Throwable ignore) {}
}
}
}
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
if (file != null) { if (file != null) {
try { if (!file.exists ()) {
FileReader fr = new FileReader (file); remove ();
EvaluationSource es = new FileEvaluationSource (file.getPath (), null); } else {
updateRequestEvaluator (reval, fr, es); lastmod = file.lastModified ();
} catch (IOException iox) { // app.typemgr.readFunctionFile (file, prototype.getName ());
app.logEvent ("Error updating function file: "+iox); // app.getScriptingEnvironment().evaluateFile (prototype, file);
} }
} else { } else {
StringReader reader = new StringReader (content); // app.getScriptingEnvironment().evaluateString (prototype, content);
StringEvaluationSource es = new StringEvaluationSource (content, null);
updateRequestEvaluator (reval, reader, es);
} }
} }
public synchronized void updateRequestEvaluator (RequestEvaluator reval, Reader reader, EvaluationSource source) { /* public void evaluate (ScriptingEnvironment env) {
if (file != null)
env.evaluateFile (prototype, file);
else
env.evaluateString (prototype, content);
}*/
public boolean hasFile () {
return file != null;
}
HashMap priorProps = null; public File getFile () {
HashSet newProps = null; return file;
}
try { public String getContent () {
return content;
ObjectPrototype op = reval.getPrototype (prototype.getName());
// extract all properties from prototype _before_ evaluation, so we can compare afterwards
// but only do this is declaredProps is not up to date yet
if (declaredPropsTimestamp != lastmod) {
priorProps = new HashMap ();
// remember properties before evaluation, so we can tell what's new afterwards
try {
for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) {
String prop = (String) en.nextElement ();
priorProps.put (prop, op.getProperty (prop, prop.hashCode()));
}
} catch (Exception ignore) {}
}
// do the update, evaluating the file
reval.evaluator.evaluate(reader, op, source, false);
// check what's new
if (declaredPropsTimestamp != lastmod) try {
newProps = new HashSet ();
for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) {
String prop = (String) en.nextElement ();
if (priorProps.get (prop) == null || op.getProperty (prop, prop.hashCode()) != priorProps.get (prop))
newProps.add (prop);
}
} catch (Exception ignore) {}
} catch (Throwable e) {
app.logEvent ("Error parsing function file "+source+": "+e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignore) {}
}
// now remove the props that were not refreshed, and set declared props to new collection
if (declaredPropsTimestamp != lastmod) {
declaredPropsTimestamp = lastmod;
if (declaredProps != null) {
declaredProps.removeAll (newProps);
removeProperties (declaredProps);
}
declaredProps = newProps;
// System.err.println ("DECLAREDPROPS = "+declaredProps);
}
}
} }
@ -185,10 +102,10 @@ public class FunctionFile implements Updatable {
prototype.updatables.remove (file.getName()); prototype.updatables.remove (file.getName());
// if we did not add anything to any evaluator, we're done // if we did not add anything to any evaluator, we're done
if (declaredProps == null || declaredProps.size() == 0) /* if (declaredProps == null || declaredProps.size() == 0)
return; return;
removeProperties (declaredProps); removeProperties (declaredProps); */
} }
/** /**
@ -199,7 +116,7 @@ public class FunctionFile implements Updatable {
void removeProperties (HashSet props) { void removeProperties (HashSet props) {
// first loop through other function files in this prototype to make a set of properties // first loop through other function files in this prototype to make a set of properties
// owned by other files. // owned by other files.
HashSet otherFiles = new HashSet (); /* HashSet otherFiles = new HashSet ();
for (Iterator it=prototype.functions.values ().iterator (); it.hasNext (); ) { for (Iterator it=prototype.functions.values ().iterator (); it.hasNext (); ) {
FunctionFile other = (FunctionFile) it.next (); FunctionFile other = (FunctionFile) it.next ();
if (other != this && other.declaredProps != null) if (other != this && other.declaredProps != null)
@ -220,7 +137,7 @@ public class FunctionFile implements Updatable {
// System.err.println ("REMOVING PROP: "+fname); // System.err.println ("REMOVING PROP: "+fname);
} }
} catch (Exception ignore) {} } catch (Exception ignore) {}
} } */
} }
public String toString () { public String toString () {
@ -234,40 +151,3 @@ public class FunctionFile implements Updatable {
} }

View file

@ -3,9 +3,11 @@
package helma.scripting; package helma.scripting;
import helma.framework.core.Application;
import helma.framework.core.Prototype;
import helma.framework.core.RequestEvaluator;
import java.util.*; import java.util.*;
import java.io.File;
/** /**
* This is the interface that must be implemented to make a scripting environment * This is the interface that must be implemented to make a scripting environment
@ -16,14 +18,30 @@ public interface ScriptingEnvironment {
/** /**
* Initialize the environment using the given properties * Initialize the environment using the given properties
*/ */
public void init (Properties props) throws ScriptingException; public void init (Application app, Properties props) throws ScriptingException;
/**
* A prototype has been updated and must be re-evaluated.
*/
public void updatePrototype (Prototype prototype);
/** /**
* Invoke a function on some object, using the given arguments and global vars. * Invoke a function on some object, using the given arguments and global vars.
*/ */
public Object invoke (Object thisObject, Object[] args, HashMap globals) throws ScriptingException; public Object invoke (Object thisObject, String functionName, Object[] args,
HashMap globals, RequestEvaluator reval)
throws ScriptingException;
/**
* Get a property on an object
*/
public Object get (Object thisObject, String key, RequestEvaluator reval);
/**
* Return true if a function by that name is defined for that object.
*/
public boolean hasFunction (Object thisObject, String functionName, RequestEvaluator reval)
throws ScriptingException;
} }
@ -51,9 +69,6 @@ public interface ScriptingEnvironment {

View file

@ -9,8 +9,8 @@ import java.util.Iterator;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import helma.framework.*; import helma.framework.*;
import helma.framework.core.*; import helma.framework.core.*;
import FESI.Data.*; // import FESI.Data.*;
import FESI.Exceptions.*; // import FESI.Exceptions.*;
/** /**
@ -24,18 +24,24 @@ import FESI.Exceptions.*;
* template files to do the formatting. * template files to do the formatting.
*/ */
public class Template extends Action { public class Template extends ActionFile {
// this is the *_as_string function, which is in addition to the normal one // this is the *_as_string function, which is in addition to the normal one
TypeUpdater psfunc; // TypeUpdater psfunc;
public Template (File file, String name, Prototype proto) { public Template (File file, String name, Prototype proto) {
super (file, name, proto); super (file, name, proto);
functionName = name;
}
public Template (String content, String name, Prototype proto) {
super (content, name, proto);
functionName = name;
} }
public void update (String content) throws Exception { public String getContent () {
// IServer.getLogger().log ("Reading text template " + name); // IServer.getLogger().log ("Reading text template " + name);
Vector partBuffer = new Vector (); Vector partBuffer = new Vector ();
@ -99,7 +105,7 @@ public class Template extends Action {
// append a CRLF // append a CRLF
newLineCount++; newLineCount++;
templateBody.append ("\\r\\n"); templateBody.append ("\\r\\n");
} else if (!"\r".equals (nextLine)){ } else if (!"\r".equals (nextLine)) try {
StringReader lineReader = new StringReader (nextLine); StringReader lineReader = new StringReader (nextLine);
int c = lineReader.read (); int c = lineReader.read ();
while (c > -1) { while (c > -1) {
@ -109,7 +115,7 @@ public class Template extends Action {
templateBody.append ((char) c); templateBody.append ((char) c);
c = lineReader.read (); c = lineReader.read ();
} }
} } catch (IOException srx) {}
nextLine = st.hasMoreTokens () ? st.nextToken () : null; nextLine = st.hasMoreTokens () ? st.nextToken () : null;
@ -137,7 +143,9 @@ public class Template extends Action {
} }
// templateBody.append ("\r\nreturn null;\r\n"); // templateBody.append ("\r\nreturn null;\r\n");
functionName = name; return templateBody.toString ();
/*
String fname = name+"_as_string"; String fname = name+"_as_string";
String body = templateBody.toString (); String body = templateBody.toString ();
@ -164,14 +172,15 @@ public class Template extends Action {
RequestEvaluator reval = (RequestEvaluator) evals.next (); RequestEvaluator reval = (RequestEvaluator) evals.next ();
updateRequestEvaluator (reval); updateRequestEvaluator (reval);
} catch (Exception ignore) {} } catch (Exception ignore) {}
} } */
} }
void remove () { protected void remove () {
prototype.templates.remove (name); prototype.templates.remove (name);
prototype.updatables.remove (file.getName()); if (file != null)
prototype.updatables.remove (file.getName());
Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); /* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) { while (evals.hasNext ()) {
try { try {
RequestEvaluator reval = (RequestEvaluator) evals.next (); RequestEvaluator reval = (RequestEvaluator) evals.next ();
@ -187,16 +196,16 @@ public class Template extends Action {
op.deleteProperty (fname, fname.hashCode()); op.deleteProperty (fname, fname.hashCode());
} }
} catch (Exception ignore) {} } catch (Exception ignore) {}
} } */
} }
public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { /* public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
if (pfunc != null) if (pfunc != null)
pfunc.updateRequestEvaluator (reval); pfunc.updateRequestEvaluator (reval);
if (psfunc != null) if (psfunc != null)
psfunc.updateRequestEvaluator (reval); psfunc.updateRequestEvaluator (reval);
} } */
class Part { class Part {
@ -224,34 +233,9 @@ public class Template extends Action {
} }
} }

View file

@ -20,11 +20,11 @@ public class ESAppNode extends ESNode {
private Application app; private Application app;
private DatePrototype createtime; private DatePrototype createtime;
public ESAppNode (INode node, RequestEvaluator eval) throws EcmaScriptException { public ESAppNode (INode node, FesiEvaluator eval) throws EcmaScriptException {
super (eval.esNodePrototype, eval.evaluator, node, eval); super (eval.getPrototype("hopobject"), eval.getEvaluator(), node, eval);
app = eval.app; app = eval.getApplication();
createtime = new DatePrototype (eval.evaluator, node.created()); createtime = new DatePrototype (evaluator, node.created());
FunctionPrototype fp = (FunctionPrototype) eval.evaluator.getFunctionPrototype(); FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
putHiddenProperty("getThreads", new AppCountThreads ("getThreads", evaluator, fp)); putHiddenProperty("getThreads", new AppCountThreads ("getThreads", evaluator, fp));
putHiddenProperty("getMaxThreads", new AppCountEvaluators ("getMaxThreads", evaluator, fp)); putHiddenProperty("getMaxThreads", new AppCountEvaluators ("getMaxThreads", evaluator, fp));
putHiddenProperty("getFreeThreads", new AppCountFreeEvaluators ("getFreeThreads", evaluator, fp)); putHiddenProperty("getFreeThreads", new AppCountFreeEvaluators ("getFreeThreads", evaluator, fp));

View file

@ -107,54 +107,3 @@ public class ESGenericObject extends ObjectPrototype {
} }

View file

@ -20,16 +20,16 @@ import java.util.*;
public class ESMapWrapper extends ESWrapper { public class ESMapWrapper extends ESWrapper {
private Map data; private Map data;
private RequestEvaluator reval; private FesiEvaluator fesi;
public ESMapWrapper (RequestEvaluator reval) { public ESMapWrapper (FesiEvaluator fesi) {
super (new Object(), reval.evaluator); super (new Object(), fesi.getEvaluator ());
this.reval = reval; this.fesi = fesi;
} }
public ESMapWrapper (RequestEvaluator reval, Map data) { public ESMapWrapper (FesiEvaluator fesi, Map data) {
super (new Object(), reval.evaluator); super (new Object(), fesi.getEvaluator ());
this.reval = reval; this.fesi = fesi;
this.data = data; this.data = data;
} }
@ -63,7 +63,7 @@ public class ESMapWrapper extends ESWrapper {
if (val instanceof String) if (val instanceof String)
return new ESString ((String) val); return new ESString ((String) val);
else if (val instanceof INode) else if (val instanceof INode)
return reval.getNodeWrapper ((INode) val); return fesi.getNodeWrapper ((INode) val);
else if (val instanceof ESValue) else if (val instanceof ESValue)
return (ESValue) val; return (ESValue) val;
return ESLoader.normalizeValue(val, evaluator); return ESLoader.normalizeValue(val, evaluator);

View file

@ -35,13 +35,13 @@ public class ESNode extends ObjectPrototype {
NodeHandle handle; NodeHandle handle;
DbMapping dbmap; DbMapping dbmap;
Throwable lastError = null; Throwable lastError = null;
RequestEvaluator eval; FesiEvaluator eval;
/** /**
* Constructor used to create transient cache nodes * Constructor used to create transient cache nodes
*/ */
public ESNode (INode node, RequestEvaluator eval) { public ESNode (INode node, FesiEvaluator eval) {
super (eval.esNodePrototype, eval.evaluator); super (eval.getPrototype("hopobject"), eval.getEvaluator());
this.eval = eval; this.eval = eval;
this.node = node; this.node = node;
cache = null; cache = null;
@ -51,7 +51,7 @@ public class ESNode extends ObjectPrototype {
handle = null; handle = null;
} }
public ESNode (ESObject prototype, Evaluator evaluator, Object obj, RequestEvaluator eval) { public ESNode (ESObject prototype, Evaluator evaluator, Object obj, FesiEvaluator eval) {
super (prototype, evaluator); super (prototype, evaluator);
// eval.app.logEvent ("in ESNode constructor: "+o.getClass ()); // eval.app.logEvent ("in ESNode constructor: "+o.getClass ());
this.eval = eval; this.eval = eval;

View file

@ -27,8 +27,8 @@ public class ESUser extends ESNode {
/** if the user is online, this is his/her online session object */ /** if the user is online, this is his/her online session object */
public User user; public User user;
public ESUser (INode node, RequestEvaluator eval, User user) { public ESUser (INode node, FesiEvaluator eval, User user) {
super (eval.esUserPrototype, eval.evaluator, node, eval); super (eval.getPrototype("user"), eval.getEvaluator(), node, eval);
this.user = user; this.user = user;
if (user != null) { if (user != null) {
cache = user.getCache (); cache = user.getCache ();

View file

@ -1,8 +1,9 @@
// Action.java // ActionFile.java
// Copyright (c) Hannes Wallnöfer 1998-2000 // Copyright (c) Hannes Wallnöfer 1998-2000
package helma.scripting; package helma.scripting.fesi;
import helma.scripting.*;
import java.util.Vector; import java.util.Vector;
import java.util.Iterator; import java.util.Iterator;
import java.io.*; import java.io.*;
@ -20,90 +21,46 @@ import FESI.Exceptions.*;
/** /**
* An Action is a JavaScript function that is exposed as a URI. It is * An class that updates fesi interpreters with actionfiles and templates.
* usually represented by a file with extension .hac (hop action file)
* that contains the pure JavaScript body of the function.
*/ */
public class Action implements Updatable { public class FesiActionAdapter {
String name;
String functionName;
Prototype prototype; Prototype prototype;
Application app; Application app;
File file; String sourceName;
long lastmod;
// this is the parsed function which can be easily applied to RequestEvaluator objects // this is the parsed function which can be easily applied to RequestEvaluator objects
TypeUpdater pfunc; TypeUpdater pfunc;
public FesiActionAdapter (ActionFile action) {
public Action (File file, String name, Prototype proto) { prototype = action.getPrototype ();
this.prototype = proto; app = action.getApplication ();
this.app = proto.getApplication (); String content = action.getContent ();
this.name = name; String functionName = action.getFunctionName ();
this.file = file; sourceName = action.toString ();
if (file != null) try {
update (); pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
} } catch (Throwable x) {
String message = x.getMessage ();
/** pfunc = new ErrorFeedback (functionName, message);
* Tell the type manager whether we need an update. this is the case when
* the file has been modified or deleted.
*/
public boolean needsUpdate () {
return lastmod != file.lastModified ();
}
public void update () {
if (!file.exists ()) {
// remove functions declared by this from all object prototypes
remove ();
} else {
try {
FileReader reader = new FileReader (file);
char cbuf[] = new char[(int) file.length ()];
reader.read (cbuf);
reader.close ();
String content = new String (cbuf);
update (content);
} catch (Exception filex) {
app.logEvent ("*** Error reading action file "+file+": "+filex);
}
lastmod = file.lastModified ();
} }
} }
/* protected void update (FesiEvaluator fesi) throws Exception {
public void update (String content) throws Exception {
// app.logEvent ("Reading text template " + name); // app.logEvent ("Reading text template " + name);
functionName = name+"_action"; FesiScriptingEnvironment scriptEnv = (FesiScriptingEnvironment) app.getScriptingEnvironment ();
Iterator evals = scriptEnv.getEvaluators().iterator();
try {
pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
} catch (Throwable x) {
String message = x.getMessage ();
pfunc = new ErrorFeedback (functionName, message);
}
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) { while (evals.hasNext ()) {
try { try {
RequestEvaluator reval = (RequestEvaluator) evals.next (); FesiEvaluator fesi = (FesiEvaluator) evals.next ();
updateRequestEvaluator (reval); updateEvaluator (fesi);
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
} } */
void remove () {
prototype.actions.remove (name);
prototype.updatables.remove (file.getName());
/* protected void remove () {
Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) { while (evals.hasNext ()) {
try { try {
@ -116,23 +73,12 @@ public class Action implements Updatable {
} }
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
} } */
public String getName () {
return name;
}
public String getFunctionName () { public synchronized void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
return functionName;
}
public String toString () {
return prototype.getName()+"/"+file.getName();
}
public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
if (pfunc != null) if (pfunc != null)
pfunc.updateRequestEvaluator (reval); pfunc.updateEvaluator (fesi);
} }
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException { protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException {
@ -176,10 +122,10 @@ public class Action implements Updatable {
sl = (ASTStatementList) parser.StatementList(); sl = (ASTStatementList) parser.StatementList();
is.close(); is.close();
} catch (ParseException x) { } catch (ParseException x) {
app.logEvent ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x); app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null)); throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null));
} catch (Exception x) { } catch (Exception x) {
app.logEvent ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x); app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
throw new RuntimeException (x.getMessage ()); throw new RuntimeException (x.getMessage ());
} }
@ -204,15 +150,15 @@ public class Action implements Updatable {
this.functionName = functionName; this.functionName = functionName;
} }
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
ObjectPrototype op = reval.getPrototype (prototype.getName()); ObjectPrototype op = fesi.getPrototype (prototype.getName());
EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor(); EcmaScriptVariableVisitor vdvisitor = fesi.evaluator.getVarDeclarationVisitor();
Vector vnames = vdvisitor.processVariableDeclarations(sl, fes); Vector vnames = vdvisitor.processVariableDeclarations(sl, fes);
FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction ( FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction (
reval.evaluator, functionName, fes, fesi.evaluator, functionName, fes,
fullFunctionText, fpl.getArguments(), vnames, sl); fullFunctionText, fpl.getArguments(), vnames, sl);
op.putHiddenProperty (functionName, fp); op.putHiddenProperty (functionName, fp);
} }
@ -228,12 +174,12 @@ public class Action implements Updatable {
errorMessage = msg; errorMessage = msg;
} }
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
ObjectPrototype op = reval.getPrototype (prototype.getName ()); ObjectPrototype op = fesi.getPrototype (prototype.getName ());
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype (); FunctionPrototype fp = (FunctionPrototype) fesi.evaluator.getFunctionPrototype ();
FunctionPrototype func = new ThrowException (functionName, reval.evaluator, fp, errorMessage); FunctionPrototype func = new ThrowException (functionName, fesi.evaluator, fp, errorMessage);
op.putHiddenProperty (functionName, func); op.putHiddenProperty (functionName, func);
} }
@ -254,38 +200,8 @@ public class Action implements Updatable {
} }
interface TypeUpdater { interface TypeUpdater {
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException; public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException;
} }
} }

View file

@ -0,0 +1,584 @@
// FesiScriptingEnvironment.java
// Copyright (c) Hannes Wallnöfer 2002
package helma.scripting.fesi;
import helma.scripting.*;
import helma.scripting.fesi.extensions.*;
import helma.framework.*;
import helma.framework.core.*;
import helma.objectmodel.*;
import helma.objectmodel.db.DbMapping;
import helma.objectmodel.db.Relation;
import helma.util.Updatable;
import java.util.*;
import java.io.*;
import FESI.Data.*;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
import Acme.LruHashtable;
/**
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
*/
public class FesiEvaluator {
// the application we're running in
public Application app;
// The FESI evaluator
Evaluator evaluator;
// the global object
GlobalObject global;
// caching table for JavaScript object wrappers
LruHashtable wrappercache;
// table containing JavaScript prototypes
Hashtable prototypes;
// the request evaluator instance owning this fesi evaluator
RequestEvaluator reval;
// extensions loaded by this evaluator
static String[] extensions = new String[] {
"FESI.Extensions.BasicIO",
"FESI.Extensions.FileIO",
"helma.xmlrpc.fesi.FesiRpcExtension",
"helma.scripting.fesi.extensions.ImageExtension",
"helma.scripting.fesi.extensions.FtpExtension",
"FESI.Extensions.JavaAccess",
"FESI.Extensions.OptionalRegExp"};
public FesiEvaluator (Application app, RequestEvaluator reval) {
this.app = app;
this.reval = reval;
wrappercache = new LruHashtable (100, .80f);
prototypes = new Hashtable ();
try {
evaluator = new Evaluator();
evaluator.reval = this;
global = evaluator.getGlobalObject();
for (int i=0; i<extensions.length; i++)
evaluator.addExtension (extensions[i]);
HopExtension hopx = new HopExtension (app);
hopx.initializeExtension (this);
MailExtension mailx = (MailExtension) evaluator.addExtension ("helma.scripting.fesi.extensions.MailExtension");
mailx.setProperties (app.getProperties ());
Database dbx = (Database) evaluator.addExtension ("helma.scripting.fesi.extensions.Database");
dbx.setApplication (app);
// fake a cache member like the one found in ESNodes
global.putHiddenProperty ("cache", new ESNode (new TransientNode ("cache"), this));
global.putHiddenProperty ("undefined", ESUndefined.theUndefined);
ESAppNode appnode = new ESAppNode (app.getAppNode (), this);
global.putHiddenProperty ("app", appnode);
initialize();
} catch (Exception e) {
System.err.println("Cannot initialize interpreter");
System.err.println("Error: " + e);
e.printStackTrace ();
throw new RuntimeException (e.getMessage ());
}
}
private void initialize () {
Collection prototypes = app.getPrototypes();
for (Iterator i=prototypes.iterator(); i.hasNext(); ) {
Prototype proto = (Prototype) i.next ();
evaluatePrototype (proto);
}
}
void evaluatePrototype (Prototype prototype) {
ObjectPrototype op = null;
// get the prototype's prototype if possible and necessary
ObjectPrototype 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) {
op = new ObjectPrototype (opp, evaluator);
try {
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
} catch (EcmaScriptException ignore) {}
putPrototype (name, op);
} else {
// set parent prototype just in case it has been changed
op.setPrototype (opp);
}
resetPrototype (op);
// Register a constructor for all types except global.
// This will first create a node and then call the actual (scripted) constructor on it.
if (!"global".equalsIgnoreCase (name)) {
try {
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
evaluator.getGlobalObject().putHiddenProperty (name, new NodeConstructor (name, fp, this));
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = prototype.functions.values().iterator(); it.hasNext(); ) {
FunctionFile ff = (FunctionFile) it.next ();
if (ff.hasFile ())
evaluateFile (prototype, ff.getFile ());
else
evaluateString (prototype, ff.getContent ());
}
/* for (Iterator it = prototype.templates.values().iterator(); it.hasNext(); ) {
Template tmp = (Template) it.next ();
try {
tmp.updateRequestEvaluator (reval);
} catch (EcmaScriptException ignore) {}
} */
for (Iterator it = prototype.actions.values().iterator(); it.hasNext(); ) {
ActionFile act = (ActionFile) it.next ();
try {
FesiActionAdapter adp = new FesiActionAdapter (act);
adp.updateEvaluator (this);
} catch (EcmaScriptException ignore) {}
}
}
/**
* Return an object prototype to its initial state, removing all application specific
* functions.
*/
void resetPrototype (ObjectPrototype op) {
for (Enumeration en = op.getAllProperties(); en.hasMoreElements(); ) {
String prop = en.nextElement ().toString ();
try {
ESValue esv = op.getProperty (prop, prop.hashCode ());
// System.err.println (protoname+"."+obj+" -> "+esv.getClass());
if (esv instanceof ConstructedFunctionObject || esv instanceof FesiActionAdapter.ThrowException)
op.deleteProperty (prop, prop.hashCode());
} catch (Exception x) {}
}
}
/**
* Invoke a function on some object, using the given arguments and global vars.
*/
public Object invoke (Object thisObject, String functionName, Object[] args, HashMap globals) throws ScriptingException {
ESObject eso = null;
if (thisObject == null)
eso = global;
else
eso = getElementWrapper (thisObject);
GlobalObject global = evaluator.getGlobalObject ();
// if we are provided with global variables to set for this invocation,
// remember the global variables before invocation to be able to reset them afterwards.
Set globalVariables = null;
try {
ESValue[] esv = args == null ? new ESValue[0] : new ESValue[args.length];
for (int i=0; i<esv.length; i++) {
// for java.util.Map objects, we use the special "tight" wrapper
// that makes the Map look like a native object
if (args[i] instanceof Map)
esv[i] = new ESMapWrapper (this, (Map) args[i]);
else
esv[i] = ESLoader.normalizeValue (args[i], evaluator);
}
if (globals != null) {
// remember all global variables before invocation
Set tmpGlobal = new HashSet ();
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
tmpGlobal.add (en.nextElement ().toString ());
}
globalVariables = tmpGlobal;
// 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);
ESValue sv = null;
// 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 (v instanceof RequestTrans)
((RequestTrans) v).data = new ESMapWrapper (this, ((RequestTrans) v).getRequestData ());
else if (v instanceof ResponseTrans)
((ResponseTrans) v).data = new ESMapWrapper (this, ((ResponseTrans) v).getResponseData ());
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;
for (int j=0; j<path.size(); j++) {
Object pathElem = path.get (j);
ESValue wrappedElement = getElementWrapper (pathElem);
parr.putProperty (j, wrappedElement);
parr.putHiddenProperty (app.getPrototypeName(pathElem), wrappedElement);
}
sv = parr;
} else if ("user".equals (k)) {
sv = getNodeWrapper ((User) v);
} else if ("app".equals (k)) {
sv = new ESAppNode ((INode) v, this);
}
else
sv = ESLoader.normalizeValue (v, evaluator);
global.putHiddenProperty (k, sv);
}
}
evaluator.thread = Thread.currentThread ();
ESValue retval = eso.doIndirectCall (evaluator, eso, functionName, esv);
return retval == null ? null : retval.toJavaObject ();
} 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 ());
// create and throw a ScriptingException with the right message
String msg = x.getMessage ();
if (msg == null || msg.length() < 10)
msg = x.toString ();
// System.err.println ("INVOKE-ERROR: "+msg);
// x.printStackTrace ();
throw new ScriptingException (msg);
} finally {
// remove global variables that have been added during invocation.
// this are typically undeclared variables, and we don't want them to
// endure from one request to the next since this leads to buggy code that
// relies on requests being served by the same evaluator, which is typically the
// case under development conditions but not in deployment.
if (globalVariables != null) {
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
String g = en.nextElement ().toString ();
if (!globalVariables.contains (g)) try {
global.deleteProperty (g, g.hashCode());
} catch (Exception x) {
System.err.println ("Error resetting global property: "+g);
}
}
}
}
}
/**
* 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) {
ESObject eso = null;
if (obj == null)
eso = evaluator.getGlobalObject ();
else
eso = getElementWrapper (obj);
try {
ESValue func = eso.getProperty (fname, fname.hashCode());
if (func != null && func instanceof FunctionPrototype)
return true;
} catch (EcmaScriptException esx) {
// System.err.println ("Error in hasFunction: "+esx);
return false;
}
return false;
}
/**
* Check if an object has a defined property (public field if it
* is a java object) with that name.
*/
public Object getProperty (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+"]";
}
}
ESObject eso = getElementWrapper (obj);
try {
ESValue prop = eso.getProperty (propname, propname.hashCode());
if (prop != null && !(prop instanceof ESNull) &&
!(prop instanceof ESUndefined))
return prop.toJavaObject ();
} catch (EcmaScriptException esx) {
// System.err.println ("Error in getProperty: "+esx);
return null;
}
return null;
}
/**
* Return the FESI Evaluator object wrapped by this object.
*/
public Evaluator getEvaluator () {
return evaluator;
}
/**
* Return the application we're running in
*/
public Application getApplication () {
return app;
}
/**
* Get the object prototype for a prototype name
*/
public ObjectPrototype getPrototype (String protoName) {
if (protoName == null)
return null;
return (ObjectPrototype) prototypes.get (protoName);
}
/**
* Register an object prototype for a certain prototype name.
*/
public void putPrototype (String protoName, ObjectPrototype op) {
if (protoName != null && op != null)
prototypes.put (protoName, op);
}
/**
* 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 ESValue getObjectWrapper (Object e) {
if (app.getPrototypeName (e) != null)
return getElementWrapper (e);
/* else if (e instanceof INode)
return new ESNode ((INode) e, this); */
else
return new ESWrapper (e, evaluator);
}
/**
* 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 ESObject getElementWrapper (Object e) {
// check if e is an instance of a helma objectmodel node.
if (e instanceof INode)
return getNodeWrapper ((INode) e);
// Gotta find out the prototype name to use for this object...
String prototypeName = app.getPrototypeName (e);
ObjectPrototype op = getPrototype (prototypeName);
if (op == null)
op = getPrototype ("hopobject");
return new ESGenericObject (op, evaluator, e);
}
/**
* Get a script wrapper for an implemntation of helma.objectmodel.INode
*/
public ESNode getNodeWrapper (INode n) {
if (n == null)
return null;
ESNode esn = (ESNode) wrappercache.get (n);
if (esn == null || esn.getNode() != n) {
String protoname = n.getPrototype ();
ObjectPrototype 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");
DbMapping dbm = n.getDbMapping ();
if (dbm != null && dbm.isInstanceOf ("user"))
esn = new ESUser (n, this, null);
else
esn = new ESNode (op, evaluator, n, this);
wrappercache.put (n, esn);
// app.logEvent ("Wrapper for "+n+" created");
}
return esn;
}
/**
* Register a new Node wrapper with the wrapper cache. This is used by the
* Node constructor.
*/
public void putNodeWrapper (INode n, ESNode esn) {
wrappercache.put (n, esn);
}
/**
* Get a scripting wrapper object for a user object. Active user objects are represented by
* the special ESUser wrapper class.
*/
public ESNode getNodeWrapper (User u) {
if (u == null)
return null;
ESUser esn = (ESUser) wrappercache.get (u);
if (esn == null) {
esn = new ESUser (u.getNode(), this, u);
wrappercache.put (u, esn);
} else {
// the user node may have changed (login/logout) while the ESUser was
// lingering in the cache.
esn.updateNodeFromUser ();
}
return esn;
}
/**
* 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;
}
public synchronized void evaluateFile (Prototype prototype, File file) {
try {
FileReader fr = new FileReader (file);
EvaluationSource es = new FileEvaluationSource (file.getPath (), null);
updateEvaluator (prototype, fr, es);
} catch (IOException iox) {
app.logEvent ("Error updating function file: "+iox);
}
}
public synchronized void evaluateString (Prototype prototype, String code) {
StringReader reader = new StringReader (code);
StringEvaluationSource es = new StringEvaluationSource (code, null);
updateEvaluator (prototype, reader, es);
}
public synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) {
// HashMap priorProps = null;
// HashSet newProps = null;
try {
ObjectPrototype op = getPrototype (prototype.getName());
// extract all properties from prototype _before_ evaluation, so we can compare afterwards
// but only do this is declaredProps is not up to date yet
/*if (declaredPropsTimestamp != lastmod) {
priorProps = new HashMap ();
// remember properties before evaluation, so we can tell what's new afterwards
try {
for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) {
String prop = (String) en.nextElement ();
priorProps.put (prop, op.getProperty (prop, prop.hashCode()));
}
} catch (Exception ignore) {}
} */
// do the update, evaluating the file
evaluator.evaluate(reader, op, source, false);
// check what's new
/* if (declaredPropsTimestamp != lastmod) try {
newProps = new HashSet ();
for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) {
String prop = (String) en.nextElement ();
if (priorProps.get (prop) == null || op.getProperty (prop, prop.hashCode()) != priorProps.get (prop))
newProps.add (prop);
}
} catch (Exception ignore) {} */
} catch (Throwable e) {
app.logEvent ("Error parsing function file "+source+": "+e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignore) {}
}
// now remove the props that were not refreshed, and set declared props to new collection
/* if (declaredPropsTimestamp != lastmod) {
declaredPropsTimestamp = lastmod;
if (declaredProps != null) {
declaredProps.removeAll (newProps);
removeProperties (declaredProps);
}
declaredProps = newProps;
// System.err.println ("DECLAREDPROPS = "+declaredProps);
} */
}
}
}

View file

@ -0,0 +1,85 @@
// FesiScriptingEnvironment.java
// Copyright (c) Hannes Wallnöfer 2002
package helma.scripting.fesi;
import helma.scripting.*;
import helma.framework.core.*;
import java.util.*;
import java.io.File;
import FESI.Data.*;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
/**
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
*/
public class FesiScriptingEnvironment implements ScriptingEnvironment {
Application app;
Properties props;
HashMap evaluators;
/**
* Initialize the environment using the given properties
*/
public void init (Application app, Properties props) throws ScriptingException {
this.app = app;
this.props = props;
evaluators = new HashMap ();
}
/**
* A prototype has been updated and must be re-evaluated.
*/
public void updatePrototype (Prototype prototype) {
for (Iterator i = evaluators.values().iterator(); i.hasNext(); ) {
FesiEvaluator fesi = (FesiEvaluator) i.next();
fesi.evaluatePrototype (prototype);
}
}
/**
* Invoke a function on some object, using the given arguments and global vars.
*/
public Object invoke (Object thisObject, String functionName, Object[] args,
HashMap globals, RequestEvaluator reval)
throws ScriptingException {
// check if there is already a FesiEvaluator for this RequestEvaluator.
// if not, create one.
FesiEvaluator fesi = getEvaluator (reval);
return fesi.invoke (thisObject, functionName, args, globals);
}
/**
* Get a property on an object
*/
public Object get (Object thisObject, String key, RequestEvaluator reval) {
FesiEvaluator fesi = getEvaluator (reval);
return fesi.getProperty (thisObject, key);
}
/**
* Return true if a function by that name is defined for that object.
*/
public boolean hasFunction (Object thisObject, String functionName, RequestEvaluator reval)
throws ScriptingException {
FesiEvaluator fesi = getEvaluator (reval);
return fesi.hasFunction (thisObject, functionName);
}
Collection getEvaluators () {
return evaluators.values();
}
FesiEvaluator getEvaluator (RequestEvaluator reval) {
FesiEvaluator fesi = (FesiEvaluator) evaluators.get (reval);
if (fesi == null) {
fesi = new FesiEvaluator (app, reval);
evaluators.put (reval, fesi);
}
return fesi;
}
}

View file

@ -18,28 +18,27 @@ import java.text.*;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
/** /**
* This is the basic Extension for FESI interpreters used in HOP. It sets up * This is the basic Extension for FESI interpreters used in Helma. It sets up
* varios constructors, global functions and properties etc. * varios constructors, global functions and properties on the HopObject prototype
* (Node objects), the user prototype, the global prototype etc.
*/ */
public class HopExtension { public class HopExtension {
protected Application app; protected Application app;
protected RequestEvaluator reval; protected FesiEvaluator fesi;
public HopExtension () { public HopExtension (Application app) {
super(); this.app = app;
} }
/** /**
* Called by the evaluator after the extension is loaded. * Called by the evaluator after the extension is loaded.
*/ */
public void initializeExtension (RequestEvaluator reval) throws EcmaScriptException { public void initializeExtension (FesiEvaluator fesi) throws EcmaScriptException {
this.fesi = fesi;
this.reval = reval; Evaluator evaluator = fesi.getEvaluator ();
this.app = reval.app;
Evaluator evaluator = reval.evaluator;
GlobalObject go = evaluator.getGlobalObject(); GlobalObject go = evaluator.getGlobalObject();
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
@ -56,42 +55,42 @@ public class HopExtension {
ESObject dp = evaluator.getDatePrototype (); ESObject dp = evaluator.getDatePrototype ();
dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp)); dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp));
sp.putHiddenProperty ("trim", new StringTrim ("trim", evaluator, fp)); sp.putHiddenProperty ("trim", new StringTrim ("trim", evaluator, fp));
// generic (Java wrapper) object prototype // generic (Java wrapper) object prototype
reval.esObjectPrototype = new ObjectPrototype (op, evaluator); ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
// the Node prototype // the Node prototype
reval.esNodePrototype = new ObjectPrototype(op, evaluator); ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
// the User prototype // the User prototype
reval.esUserPrototype = new ObjectPrototype (reval.esNodePrototype, evaluator); ObjectPrototype esUserPrototype = new ObjectPrototype (esNodePrototype, evaluator);
// the Node constructor // the Node constructor
ESObject node = new NodeConstructor ("Node", fp, reval); ESObject node = new NodeConstructor ("Node", fp, fesi);
// register the default methods of Node objects in the Node prototype // register the default methods of Node objects in the Node prototype
reval.esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp)); esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp)); esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp)); esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp)); esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp)); esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp)); esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp)); esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp)); esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp)); esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp)); esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp)); esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp)); esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp)); esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp)); esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp)); esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false)); esNodePrototype.putHiddenProperty ("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
reval.esNodePrototype.putHiddenProperty ("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true)); esNodePrototype.putHiddenProperty ("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
reval.esNodePrototype.putHiddenProperty ("clearCache", new NodeClearCache ("clearCache", evaluator, fp)); esNodePrototype.putHiddenProperty ("clearCache", new NodeClearCache ("clearCache", evaluator, fp));
// default methods for generic Java wrapper object prototype. // default methods for generic Java wrapper object prototype.
// This is a small subset of the methods in esNodePrototype. // This is a small subset of the methods in esNodePrototype.
reval.esObjectPrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp)); esObjectPrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
reval.esObjectPrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false)); esObjectPrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
reval.esObjectPrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true)); esObjectPrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
// methods that give access to properties and global user lists // methods that give access to properties and global user lists
go.putHiddenProperty("Node", node); // register the constructor for a plain Node object. go.putHiddenProperty("Node", node); // register the constructor for a plain Node object.
@ -122,14 +121,19 @@ public class HopExtension {
go.deleteProperty("exit", "exit".hashCode()); go.deleteProperty("exit", "exit".hashCode());
// and some methods for session management from JS... // and some methods for session management from JS...
reval.esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp)); esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp)); esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp)); esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp)); esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp)); esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp)); esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp)); esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
// register object prototypes with FesiEvaluator
fesi.putPrototype ("global", go);
fesi.putPrototype ("hopobject", esNodePrototype);
fesi.putPrototype ("__javaobject__", esObjectPrototype);
fesi.putPrototype ("user", esUserPrototype);
} }
class NodeAdd extends BuiltinFunctionObject { class NodeAdd extends BuiltinFunctionObject {
@ -437,7 +441,7 @@ public class HopExtension {
if (unode == null) if (unode == null)
return ESNull.theNull; return ESNull.theNull;
else else
return reval.getNodeWrapper (unode); return fesi.getNodeWrapper (unode);
} }
} }
@ -552,12 +556,13 @@ public class HopExtension {
} }
public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException { public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull) if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull)
throw new EcmaScriptException ("renderSkin must be called with one Skin argument and an optional parameter argument"); throw new EcmaScriptException ("renderSkin requires one argument containing the skin name and an optional parameter object argument");
try { try {
Skin skin = null; Skin skin = null;
ESObject thisObject = global ? null : thisObj; ESObject thisObject = global ? null : thisObj;
HashMap params = null; HashMap params = null;
if (arguments.length > 1 && arguments[1] instanceof ESObject) { if (arguments.length > 1 && arguments[1] instanceof ESObject) {
// create an parameter object to pass to the skin
ESObject paramObject = (ESObject) arguments[1]; ESObject paramObject = (ESObject) arguments[1];
params = new HashMap (); params = new HashMap ();
for (Enumeration en=paramObject.getProperties(); en.hasMoreElements(); ) { for (Enumeration en=paramObject.getProperties(); en.hasMoreElements(); ) {
@ -573,17 +578,29 @@ public class HopExtension {
skin = (Skin) obj; skin = (Skin) obj;
} }
// if res.skinpath is set, transform it into an array of java objects
// (strings for directory names and INodes for internal, db-stored skinsets)
ResponseTrans res = fesi.getResponse();
Object[] skinpath = new Object[0];
if (res.skinpath != null && res.skinpath instanceof ArrayPrototype) {
ArrayPrototype array = (ArrayPrototype) res.skinpath;
skinpath = new Object[array.size()];
for (int i=0; i<skinpath.length; i++)
skinpath[i] = array.getProperty(i).toJavaObject ();
}
// ready... retrieve the skin and render it.
Object javaObject = thisObject == null ? null : thisObject.toJavaObject ();
if (skin == null) if (skin == null)
skin = reval.getSkin (thisObject, arguments[0].toString ()); skin = app.getSkin (javaObject, arguments[0].toString (), skinpath);
if (asString) if (asString)
reval.res.pushStringBuffer (); res.pushStringBuffer ();
Object javaObj = thisObject == null ? null : thisObject.toJavaObject ();
if (skin != null) if (skin != null)
skin.render (reval, javaObj, params); skin.render (fesi.getRequestEvaluator(), javaObject, params);
else else
reval.res.write ("[Skin not found: "+arguments[0]+"]"); res.write ("[Skin not found: "+arguments[0]+"]");
if (asString) if (asString)
return new ESString (reval.res.popStringBuffer ()); return new ESString (res.popStringBuffer ());
} catch (RedirectException redir) { } catch (RedirectException redir) {
// let redirect pass through // let redirect pass through
throw redir; throw redir;
@ -602,14 +619,14 @@ public class HopExtension {
super (fp, evaluator, name, 1); super (fp, evaluator, name, 1);
} }
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
INode user = null; INode user = null;
if (arguments.length > 0) { if (arguments.length > 0) {
String uname = arguments[0].toString ().trim (); String uname = arguments[0].toString ().trim ();
user = app.getUserNode (uname); user = app.getUserNode (uname);
} }
if (user == null) if (user == null)
return ESNull.theNull; return ESNull.theNull;
return reval.getNodeWrapper (user); return fesi.getNodeWrapper (user);
} }
} }
@ -618,15 +635,15 @@ public class HopExtension {
super (fp, evaluator, name, 1); super (fp, evaluator, name, 1);
} }
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
User user = null; User user = null;
if (arguments.length > 0) { if (arguments.length > 0) {
String sid = arguments[0].toString ().trim (); String sid = arguments[0].toString ().trim ();
user = app.getUser (sid); user = app.getUser (sid);
} }
if (user == null || user.getUID() == null) if (user == null || user.getUID() == null)
return ESNull.theNull; return ESNull.theNull;
user.touch (); user.touch ();
return reval.getNodeWrapper (user.getNode ()); return fesi.getNodeWrapper (user.getNode ());
} }
} }
@ -663,7 +680,7 @@ public class HopExtension {
User u = (User) e.nextElement (); User u = (User) e.nextElement ();
// Note: we previously sorted out duplicate users - now we simply enumerate all active sessions. // Note: we previously sorted out duplicate users - now we simply enumerate all active sessions.
// if (u.uid == null || !visited.containsKey (u.uid)) { // if (u.uid == null || !visited.containsKey (u.uid)) {
theArray.setElementAt (reval.getNodeWrapper (u), i++); theArray.setElementAt (fesi.getNodeWrapper (u), i++);
// if (u.uid != null) visited.put (u.uid, u); // if (u.uid != null) visited.put (u.uid, u);
// } // }
} }
@ -901,18 +918,6 @@ public class HopExtension {
} }
} }
/* class NodePath extends BuiltinFunctionObject {
NodePath (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
INode n = ((ESNode) thisObject).getNode ();
String tmpname = arguments[0].toString ();
return new ESString (app.getNodePath (n, tmpname));
}
} */
class NodeSetParent extends BuiltinFunctionObject { class NodeSetParent extends BuiltinFunctionObject {
NodeSetParent (String name, Evaluator evaluator, FunctionPrototype fp) { NodeSetParent (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 2); super (fp, evaluator, name, 2);
@ -964,11 +969,11 @@ public class HopExtension {
return new ESString (basicHref); return new ESString (basicHref);
} }
private ESString renderSkin (Skin skin, String path, Object skinElem) throws EcmaScriptException { private ESString renderSkin (Skin skin, String path, Object skinElem) throws EcmaScriptException {
reval.res.pushStringBuffer (); fesi.getResponse().pushStringBuffer ();
HashMap param = new HashMap (); HashMap param = new HashMap ();
param.put ("path", path); param.put ("path", path);
skin.render (reval, skinElem, param); skin.render (fesi.getRequestEvaluator(), skinElem, param);
return new ESString (reval.res.popStringBuffer ().trim ()); return new ESString (fesi.getResponse().popStringBuffer ().trim ());
} }
} }
@ -985,7 +990,7 @@ public class HopExtension {
double d = from <= to ? 1.0 : -1.0; double d = from <= to ? 1.0 : -1.0;
for (double i=from; i*d<=to*d; i+=step) { for (double i=from; i*d<=to*d; i+=step) {
if (Math.abs (i%1) < l) { if (Math.abs (i%1) < l) {
int j = (int) i; int j = (int) i;
b.append ("<option value=\""+j); b.append ("<option value=\""+j);
if (i == value) b.append ("\" selected=\"true"); if (i == value) b.append ("\" selected=\"true");
b.append ("\">"+j); b.append ("\">"+j);
@ -999,164 +1004,6 @@ public class HopExtension {
return b.toString (); return b.toString ();
} }
private String getNodeChooserDD (String name, INode collection, INode target, String teaser) {
StringBuffer buffer = new StringBuffer ("<select name=\"");
buffer.append (name);
buffer.append ("\">");
if (collection.contains (target) == -1) {
buffer.append ("<option value=>");
buffer.append (HtmlEncoder.encodeAll (teaser));
}
if (collection != null) {
int l = collection.numberOfNodes ();
for (int i=0; i<l; i++) {
INode next = collection.getSubnodeAt (i);
buffer.append ("<option value=\"");
buffer.append (next.getID ());
if (target == next)
buffer.append ("\" selected=\"true");
buffer.append ("\">");
String cname = next.getString ("name", false);
if (cname == null) cname = next.getName ();
buffer.append (HtmlEncoder.encodeAll (cname));
}
}
buffer.append ("</select>");
return buffer.toString ();
}
private String getNodeChooserRB (String name, INode collection, INode target) {
StringBuffer buffer = new StringBuffer ();
if (collection != null) {
int l = collection.numberOfNodes ();
for (int i=0; i<l; i++) {
INode next = collection.getSubnodeAt (i);
buffer.append ("<input type=radio name=\"");
buffer.append (name);
buffer.append ("\" value=\"");
buffer.append (next.getElementName ()+"\"");
if (target == next)
buffer.append (" checked");
buffer.append (">");
String cname = next.getString ("name", false);
if (cname == null) cname = next.getName ();
buffer.append (HtmlEncoder.encodeAll (cname));
buffer.append ("<br>");
}
}
return buffer.toString ();
}
private String getNodeChooserCB (String name, INode collection, INode target) {
StringBuffer buffer = new StringBuffer ();
if (collection != null) {
int l = collection.numberOfNodes ();
for (int i=0; i<l; i++) {
INode next = collection.getSubnodeAt (i);
buffer.append ("<input type=checkbox name=\"");
buffer.append (name);
buffer.append ("\" value=");
buffer.append (next.getElementName ());
if (target.contains (next) > -1)
buffer.append (" checked");
buffer.append (">");
buffer.append (HtmlEncoder.encodeAll (next.getName ()));
buffer.append ("<br>");
}
}
return buffer.toString ();
}
} }

View file

@ -16,13 +16,13 @@ import FESI.Interpreter.*;
public class NodeConstructor extends BuiltinFunctionObject { public class NodeConstructor extends BuiltinFunctionObject {
RequestEvaluator reval; FesiEvaluator fesi;
String typename; String typename;
public NodeConstructor (String name, FunctionPrototype fp, RequestEvaluator reval) { public NodeConstructor (String name, FunctionPrototype fp, FesiEvaluator fesi) {
super(fp, reval.evaluator, name, 1); super(fp, fesi.getEvaluator (), name, 1);
typename = name; typename = name;
this.reval = reval; this.fesi = fesi;
} }
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
@ -31,35 +31,33 @@ public class NodeConstructor extends BuiltinFunctionObject {
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = null; ESNode node = null;
Application app = fesi.getApplication ();
if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) { if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) {
if (arguments.length == 0) { String nodeName = null;
Node n = new Node ((String) null, (String) null, reval.app.getWrappedNodeManager ()); if (arguments.length > 0 && arguments[0] != null)
node = new ESNode (reval.esNodePrototype, this.evaluator, n, reval); nodeName = arguments[0].toString();
reval.objectcache.put (node.getNode (), node); Node n = new Node (nodeName, (String) null, app.getWrappedNodeManager ());
} else { node = new ESNode (fesi.getPrototype ("hopobject"), this.evaluator, n, fesi);
Node n = new Node (arguments[0].toString(), (String) null, reval.app.getWrappedNodeManager ()); fesi.putNodeWrapper (node.getNode (), node);
node = new ESNode (reval.esNodePrototype, this.evaluator, n, reval);
reval.objectcache.put (node.getNode (), node);
}
} else { } else {
// Typed nodes are instantiated as helma.objectmodel.db.Node from the beginning // Typed nodes are instantiated as helma.objectmodel.db.Node from the beginning
// even if we don't know yet if they are going to be stored in a database. The reason // even if we don't know yet if they are going to be stored in a database. The reason
// is that we want to be able to use the specail features like subnode relations even for // is that we want to be able to use the specail features like subnode relations even for
// transient nodes. // transient nodes.
ObjectPrototype op = reval.getPrototype (typename); ObjectPrototype op = fesi.getPrototype (typename);
Node n = new Node (typename, typename, reval.app.getWrappedNodeManager ()); Node n = new Node (typename, typename, app.getWrappedNodeManager ());
node = new ESNode (op, reval.evaluator, n, reval); node = new ESNode (op, fesi.getEvaluator (), n, fesi);
node.setPrototype (typename); node.setPrototype (typename);
node.getNode ().setDbMapping (reval.app.getDbMapping (typename)); node.getNode ().setDbMapping (app.getDbMapping (typename));
try { try {
// first try calling "constructor", if that doesn't work, try calling a function // first try calling "constructor", if that doesn't work, try calling a function
// with the name of the type. // with the name of the type.
// HACK: There is an incompatibility problem here, because the property // HACK: There is an incompatibility problem here, because the property
// constructor is defined as the constructor of the object by EcmaScript. // constructor is defined as the constructor of the object by EcmaScript.
if (op.getProperty("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject) if (op.getProperty ("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
node.doIndirectCall (reval.evaluator, node, "constructor", arguments); node.doIndirectCall (fesi.getEvaluator(), node, "constructor", arguments);
else else
node.doIndirectCall (reval.evaluator, node, typename, arguments); node.doIndirectCall (fesi.getEvaluator(), node, typename, arguments);
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
return node; return node;
@ -70,9 +68,9 @@ public class NodeConstructor extends BuiltinFunctionObject {
} }
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
if ("prototype".equals (propertyName)) if ("prototype".equals (propertyName))
return reval.getPrototype (typename); return fesi.getPrototype (typename);
return super.getProperty(propertyName, hash); return super.getProperty(propertyName, hash);
} }
public String[] getSpecialPropertyNames() { public String[] getSpecialPropertyNames() {