Pretty much reworked all the Helma type management code.

This commit is contained in:
hns 2002-10-22 16:33:03 +00:00
parent ea5edf51c9
commit 7463553a95
11 changed files with 360 additions and 360 deletions

View file

@ -25,16 +25,14 @@ public final class Prototype {
String name; String name;
Application app; Application app;
HashMap templates; HashMap code, zippedCode;
HashMap functions; HashMap skins, zippedSkins;
HashMap actions;
HashMap skins;
HashMap updatables; HashMap updatables;
// a map of this prototype's skins as raw strings // a map of this prototype's skins as raw strings
// used for exposing skins to application (script) code (via app.skinfiles). // used for exposing skins to application (script) code (via app.skinfiles).
SkinMap skinMap; SkinMap skinMap;
DbMapping dbmap; DbMapping dbmap;
// lastCheck is the time the prototype's files were last checked // lastCheck is the time the prototype's files were last checked
@ -54,12 +52,12 @@ public final class Prototype {
this.app = app; this.app = app;
this.name = name; this.name = name;
templates = new HashMap (); code = new HashMap ();
functions = new HashMap (); zippedCode = new HashMap ();
actions = new HashMap ();
skins = new HashMap (); skins = new HashMap ();
zippedSkins = new HashMap ();
updatables = new HashMap (); updatables = new HashMap ();
skinMap = new SkinMap (); skinMap = new SkinMap ();
isJavaPrototype = app.isJavaPrototype (name); isJavaPrototype = app.isJavaPrototype (name);
@ -96,35 +94,11 @@ public final class Prototype {
public void setDbMapping (DbMapping dbmap) { public void setDbMapping (DbMapping dbmap) {
this.dbmap = dbmap; this.dbmap = dbmap;
} }
public DbMapping getDbMapping () { public DbMapping getDbMapping () {
return dbmap; return dbmap;
} }
/**
* Get a template defined for this prototype. Templates
* are files that mix layout and code and were used
* before skins came along. Think of them as legacy.
*/
public Template getTemplate (String tmpname) {
return (Template) templates.get (tmpname);
}
/**
* Get a generic function file defined for this prototype.
*/
public FunctionFile getFunctionFile (String ffname) {
return (FunctionFile) functions.get (ffname);
}
/**
* Get an action file defined for this prototype. Action
* files are functions with a .hac extension
* that are accessible publicly via web interface.
*/
public ActionFile getActionFile (String afname) {
return (ActionFile) actions.get (afname);
}
/** /**
* Get a Skinfile for this prototype. This only works for skins * Get a Skinfile for this prototype. This only works for skins
@ -132,7 +106,10 @@ public final class Prototype {
* other locations or database stored skins. * other locations or database stored skins.
*/ */
public SkinFile getSkinFile (String sfname) { public SkinFile getSkinFile (String sfname) {
return (SkinFile) skins.get (sfname); SkinFile sf = (SkinFile) skins.get (sfname);
if (sf == null)
sf = (SkinFile) zippedSkins.get (sfname);
return sf;
} }
/** /**
@ -141,7 +118,7 @@ public final class Prototype {
* other locations or database stored skins. * other locations or database stored skins.
*/ */
public Skin getSkin (String sfname) { public Skin getSkin (String sfname) {
SkinFile sf = (SkinFile) skins.get (sfname); SkinFile sf = getSkinFile (sfname);
if (sf != null) if (sf != null)
return sf.getSkin (); return sf.getSkin ();
else else
@ -153,7 +130,7 @@ public final class Prototype {
return name; return name;
} }
Updatable[] upd = null; /* Updatable[] upd = null;
public Updatable[] getUpdatables () { public Updatable[] getUpdatables () {
if (upd == null) { if (upd == null) {
upd = new Updatable[updatables.size()]; upd = new Updatable[updatables.size()];
@ -163,7 +140,7 @@ public final class Prototype {
} }
} }
return upd; return upd;
} } */
/** /**
* Get the last time any script has been re-read for this prototype. * Get the last time any script has been re-read for this prototype.
@ -190,20 +167,20 @@ public final class Prototype {
} }
/** /**
* Signal that the prototype's scripts have been checked for * Signal that the prototype's scripts have been checked for
* changes. * changes.
*/ */
public void markChecked () { public void markChecked () {
lastCheck = System.currentTimeMillis (); lastCheck = System.currentTimeMillis ();
} }
/** /**
* Return a clone of this prototype's actions container. Synchronized * Return a clone of this prototype's actions container. Synchronized
* to not return a map in a transient state where it is just being * to not return a map in a transient state where it is just being
* updated by the type manager. * updated by the type manager.
*/ */
public synchronized Map getActions () { public synchronized Map getCode () {
return (Map) actions.clone(); return (Map) code.clone();
} }
/** /**
@ -211,46 +188,90 @@ public final class Prototype {
* to not return a map in a transient state where it is just being * to not return a map in a transient state where it is just being
* updated by the type manager. * updated by the type manager.
*/ */
public synchronized Map getFunctions () { public synchronized Map getZippedCode () {
return (Map) functions.clone(); return (Map) zippedCode.clone();
} }
/**
* Return a clone of this prototype's templates container. Synchronized public synchronized void addActionFile (ActionFile action) {
* to not return a map in a transient state where it is just being File f = action.getFile ();
* updated by the type manager. if (f != null) {
*/ code.put (action.getSourceName(), action);
public synchronized Map getTemplates () { updatables.put (f.getName(), action);
return (Map) templates.clone(); } else {
zippedCode.put (action.getSourceName(), action);
}
} }
/** public synchronized void addTemplate (Template template) {
* Return a clone of this prototype's skins container. Synchronized File f = template.getFile ();
* to not return a map in a transient state where it is just being if (f != null) {
* updated by the type manager. code.put (template.getSourceName(), template);
*/ updatables.put (f.getName(), template);
public synchronized Map getSkins () { } else {
return (Map) skins.clone(); zippedCode.put (template.getSourceName(), template);
}
} }
public synchronized void removeUpdatable (String fileName) { public synchronized void addFunctionFile (FunctionFile funcfile) {
updatables.remove (fileName); File f = funcfile.getFile ();
markUpdated (); if (f != null) {
code.put (funcfile.getSourceName(), funcfile);
updatables.put (f.getName(), funcfile);
} else {
zippedCode.put (funcfile.getSourceName(), funcfile);
}
} }
public synchronized void removeAction (String actionName) { public synchronized void addSkinFile (SkinFile skinfile) {
actions.remove (actionName); File f = skinfile.getFile ();
markUpdated (); if (f != null) {
skins.put (skinfile.getName(), skinfile);
updatables.put (f.getName(), skinfile);
} else {
zippedSkins.put (skinfile.getName(), skinfile);
}
} }
public synchronized void removeFunctionFile (String functionFileName) {
functions.remove (functionFileName); public synchronized void removeActionFile (ActionFile action) {
markUpdated (); File f = action.getFile ();
if (f != null) {
code.remove (action.getSourceName());
updatables.remove (f.getName());
} else {
zippedCode.remove (action.getSourceName());
}
} }
public synchronized void removeTemplate (String templateName) { public synchronized void removeFunctionFile (FunctionFile funcfile) {
templates.remove (templateName); File f = funcfile.getFile ();
markUpdated (); if (f != null) {
code.remove (funcfile.getSourceName());
updatables.remove (f.getName());
} else {
zippedCode.remove (funcfile.getSourceName());
}
}
public synchronized void removeTemplate (Template template) {
File f = template.getFile ();
if (f != null) {
code.remove (template.getSourceName());
updatables.remove (f.getName());
} else {
zippedCode.remove (template.getSourceName());
}
}
public synchronized void removeSkinFile (SkinFile skinfile) {
File f = skinfile.getFile ();
if (f != null) {
skins.remove (skinfile.getName());
updatables.remove (f.getName());
} else {
zippedSkins.remove (skinfile.getName());
}
} }

View file

@ -108,9 +108,7 @@ public final class RequestEvaluator implements Runnable {
// used for logging // used for logging
String txname = app.getName()+"/"+req.path; String txname = app.getName()+"/"+req.path;
// set Timer to get some profiling data // begin transaction
localrtx.timer.reset ();
localrtx.timer.beginEvent (requestPath+" init");
localrtx.begin (txname); localrtx.begin (txname);
String action = null; String action = null;
@ -221,15 +219,12 @@ public final class RequestEvaluator implements Runnable {
throw new FrameworkException (notfound.getMessage ()); throw new FrameworkException (notfound.getMessage ());
} }
localrtx.timer.endEvent (txname+" init");
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// end of path resolution section // end of path resolution section
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// beginning of execution section // beginning of execution section
try { try {
localrtx.timer.beginEvent (txname+" execute");
// enter execution context // enter execution context
scriptingEngine.enterContext (globals); scriptingEngine.enterContext (globals);
@ -255,7 +250,6 @@ public final class RequestEvaluator implements Runnable {
// do the actual action invocation // do the actual action invocation
scriptingEngine.invoke (currentElement, action, new Object[0], false); scriptingEngine.invoke (currentElement, action, new Object[0], false);
localrtx.timer.endEvent (txname+" execute");
} catch (RedirectException redirect) { } catch (RedirectException redirect) {
// res.redirect = redirect.getMessage (); // res.redirect = redirect.getMessage ();
// if there is a message set, save it on the user object for the next request // if there is a message set, save it on the user object for the next request
@ -296,28 +290,30 @@ public final class RequestEvaluator implements Runnable {
} catch (Exception x) { } catch (Exception x) {
abortTransaction (false);
app.logEvent ("### Exception in "+Thread.currentThread()+": "+x);
// Dump the profiling data to System.err
if (app.debug) {
((Transactor) Thread.currentThread ()).timer.dump (System.err);
x.printStackTrace ();
}
// If the transactor thread has been killed by the invoker thread we don't have to // If the transactor thread has been killed by the invoker thread we don't have to
// bother for the error message, just quit. // bother for the error message, just quit.
if (localrtx != rtx) if (localrtx != rtx) {
abortTransaction (false);
break; break;
}
res.reset (); res.reset ();
// check if we tried to process the error already
if (error == null) { if (error == null) {
abortTransaction (false);
app.errorCount += 1; app.errorCount += 1;
app.logEvent ("Exception in "+Thread.currentThread()+": "+x);
// Dump the profiling data to System.err
if (app.debug) {
x.printStackTrace ();
}
// set done to false so that the error will be processed // set done to false so that the error will be processed
done = false; done = false;
error = x.getMessage (); error = x.getMessage ();
if (error == null || error.length() == 0) if (error == null || error.length() == 0)
error = x.toString (); error = x.toString ();
if (error == null)
error = "Unspecified error";
} else { } else {
// error in error action. use traditional minimal error message // error in error action. use traditional minimal error message
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>"+error+"</pre>"); res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>"+error+"</pre>");

View file

@ -173,7 +173,6 @@ public final class Skin {
this.start = start; this.start = start;
this.end = end; this.end = end;
int state = HANDLER; int state = HANDLER;
boolean escape = false; boolean escape = false;
char quotechar = '\u0000'; char quotechar = '\u0000';
@ -383,6 +382,8 @@ public final class Skin {
// System.err.println ("Getting macro from function"); // System.err.println ("Getting macro from function");
// pass a clone of the parameter map so if the script changes it, // pass a clone of the parameter map so if the script changes it,
// Map param = ; // Map param = ;
// if (parameters == null)
// parameters = new HashMap ();
Object[] arguments = { parameters == null ? Object[] arguments = { parameters == null ?
new HashMap () : new HashMap () :
new HashMap (parameters) }; new HashMap (parameters) };

View file

@ -24,10 +24,10 @@ public final class SkinFile implements Updatable {
public SkinFile (File file, String name, Prototype proto) { public SkinFile (File file, String name, Prototype proto) {
this.prototype = proto; this.prototype = proto;
this.app = proto.app;
this.name = name;
this.file = file; this.file = file;
this.skin = null; this.name = name;
app = proto.app;
skin = null;
} }
/** /**
@ -37,22 +37,22 @@ public final class SkinFile implements Updatable {
*/ */
public SkinFile (String body, String name, Prototype proto) { public SkinFile (String body, String name, Prototype proto) {
this.prototype = proto; this.prototype = proto;
this.app = proto.app; app = proto.app;
this.name = name; name = name;
this.file = null; file = null;
this.skin = new Skin (body, app); skin = new Skin (body, app);
} }
/** /**
* Create a skinfile without that doesn't belong to a prototype, or at * Create a skinfile that doesn't belong to a prototype, or at
* least it doesn't know about its prototype and isn't managed by the prototype. * least it doesn't know about its prototype and isn't managed by the prototype.
*/ */
public SkinFile (File file, String name, Application app) { public SkinFile (File file, String name, Application app) {
this.prototype = null;
this.app = app; this.app = app;
this.name = name;
this.file = file; this.file = file;
this.skin = null; this.name = name;
prototype = null;
skin = null;
} }
@ -66,7 +66,6 @@ public final class SkinFile implements Updatable {
public void update () { public void update () {
if (!file.exists ()) { if (!file.exists ()) {
// remove skin from prototype // remove skin from prototype
remove (); remove ();
@ -87,19 +86,20 @@ public final class SkinFile implements Updatable {
} catch (IOException x) { } catch (IOException x) {
app.logEvent ("Error reading Skin "+file+": "+x); app.logEvent ("Error reading Skin "+file+": "+x);
} }
lastmod = file.lastModified (); lastmod = file.lastModified ();
} }
public void remove () { public void remove () {
if (prototype != null) { if (prototype != null) {
prototype.skins.remove (name); prototype.removeSkinFile (this);
if (file != null)
prototype.updatables.remove (file.getName());
} }
} }
public File getFile () {
return file;
}
public Skin getSkin () { public Skin getSkin () {
if (skin == null) if (skin == null)
read (); read ();

View file

@ -226,127 +226,109 @@ public final class TypeManager {
public void updatePrototype (Prototype proto) { public void updatePrototype (Prototype proto) {
if (proto == null) if (proto == null)
return; return;
// System.err.println ("UPDATE PROTO: "+app.getName()+"/"+proto.getName());
// if prototype has been checked in the last second, return
// if (System.currentTimeMillis() - proto.getLastCheck() < 1000)
// return;
synchronized (proto) { synchronized (proto) {
// check again because another thread may have checked the // check again because another thread may have checked the
// prototype while we were waiting for access to the synchronized section // prototype while we were waiting for access to the synchronized section
if (System.currentTimeMillis() - proto.getLastCheck() < 1000) if (System.currentTimeMillis() - proto.getLastCheck() < 1000)
return; return;
File dir = new File (appDir, proto.getName()); File dir = new File (appDir, proto.getName());
boolean needsUpdate = false; HashSet updateSet = null;
HashSet updatables = null; HashSet createSet = null;
// our plan is to do as little as possible, so first check if // our plan is to do as little as possible, so first check if
// anything the prototype knows about has changed on disk // anything the prototype knows about has changed on disk
for (Iterator i = proto.updatables.values().iterator(); i.hasNext(); ) { for (Iterator i = proto.updatables.values().iterator(); i.hasNext(); ) {
Updatable upd = (Updatable) i.next(); Updatable upd = (Updatable) i.next();
if (upd.needsUpdate ()) { if (upd.needsUpdate ()) {
if (updatables == null) if (updateSet == null)
updatables = new HashSet (); updateSet = new HashSet ();
needsUpdate = true; updateSet.add (upd);
updatables.add (upd); }
} }
}
// next we check if files have been created or removed since last update // next we check if files have been created or removed since last update
if (proto.getLastCheck() < dir.lastModified ()) { if (proto.getLastCheck() < dir.lastModified ()) {
String[] list = dir.list(); String[] list = dir.list();
for (int i=0; i<list.length; i++) { for (int i=0; i<list.length; i++) {
String fn = list[i]; String fn = list[i];
if (!proto.updatables.containsKey (fn)) { if (!proto.updatables.containsKey (fn)) {
if (fn.endsWith (templateExtension) || fn.endsWith (scriptExtension) || if (fn.endsWith (templateExtension) ||
fn.endsWith (actionExtension) || fn.endsWith (skinExtension) || fn.endsWith (scriptExtension) ||
"type.properties".equalsIgnoreCase (fn)) { fn.endsWith (actionExtension) ||
needsUpdate = true; fn.endsWith (skinExtension) ||
// updatables.add ("[new:"+proto.getName()+"/"+fn+"]"); "type.properties".equalsIgnoreCase (fn))
{
if (createSet == null)
createSet = new HashSet ();
createSet.add (list[i]);
}
} }
} }
} }
}
// if nothing needs to be updated, mark prototype as checked and return // if nothing needs to be updated, mark prototype as checked and return
if (!needsUpdate) { if (updateSet == null && createSet == null) {
proto.markChecked ();
return;
}
// first go through new files and create new items
if (createSet != null) {
Object[] newFiles = createSet.toArray ();
for (int i=0; i<newFiles.length; i++) {
String filename = (String) newFiles[i];
int dot = filename.lastIndexOf (".");
String tmpname = filename.substring(0, dot);
File tmpfile = new File (dir, filename);
if (filename.endsWith (templateExtension)) {
try {
Template t = new Template (tmpfile, tmpname, proto);
proto.addTemplate (t);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (filename.endsWith (scriptExtension)) {
try {
FunctionFile ff = new FunctionFile (tmpfile, proto);
proto.addFunctionFile (ff);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (filename.endsWith (actionExtension)) {
try {
ActionFile af = new ActionFile (tmpfile, tmpname, proto);
proto.addActionFile (af);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (filename.endsWith (skinExtension)) {
SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
proto.addSkinFile (sf);
}
}
}
// next go through existing updatables
if (updateSet != null) {
for (Iterator i = updateSet.iterator(); i.hasNext(); ) {
Updatable upd = (Updatable) i.next();
try {
upd.update ();
} catch (Exception x) {
if (upd instanceof DbMapping)
app.logEvent ("Error updating db mapping for type "+proto.getName()+": "+x);
else
app.logEvent ("Error updating "+upd+" of prototye type "+proto.getName()+": "+x);
}
}
}
// mark prototype as checked and updated.
proto.markChecked (); proto.markChecked ();
return; proto.markUpdated();
}
// app.logEvent ("TypeManager: Updating prototypes for "+app.getName()+": "+updatables);
// first go through new files and create new items
String[] list = dir.list ();
for (int i=0; i<list.length; i++) {
String fn = list[i];
int dot = fn.lastIndexOf (".");
if (dot < 0)
continue;
if (proto.updatables.containsKey (fn) || !(fn.endsWith (templateExtension) || fn.endsWith (scriptExtension) ||
fn.endsWith (actionExtension) || fn.endsWith (skinExtension) || "type.properties".equalsIgnoreCase (fn))) {
continue;
}
String tmpname = list[i].substring(0, dot);
File tmpfile = new File (dir, list[i]);
if (list[i].endsWith (templateExtension)) {
try {
Template t = new Template (tmpfile, tmpname, proto);
proto.updatables.put (list[i], t);
proto.templates.put (tmpname, t);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (list[i].endsWith (scriptExtension)) {
try {
FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto);
proto.updatables.put (list[i], ff);
proto.functions.put (tmpname, ff);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (list[i].endsWith (actionExtension)) {
try {
ActionFile af = new ActionFile (tmpfile, tmpname, proto);
proto.updatables.put (list[i], af);
proto.actions.put (tmpname, af);
} catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x);
}
} else if (list[i].endsWith (skinExtension)) {
SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
proto.updatables.put (list[i], sf);
proto.skins.put (tmpname, sf);
}
}
// next go through existing updatables
if (updatables != null) {
for (Iterator i = updatables.iterator(); i.hasNext(); ) {
Updatable upd = (Updatable) i.next();
try {
upd.update ();
} catch (Exception x) {
if (upd instanceof DbMapping)
app.logEvent ("Error updating db mapping for type "+proto.getName()+": "+x);
else
app.logEvent ("Error updating "+upd+" of prototye type "+proto.getName()+": "+x);
}
}
}
// mark prototype as checked and updated.
proto.markChecked ();
proto.markUpdated();
} // end of synchronized (proto) } // end of synchronized (proto)

View file

@ -72,20 +72,22 @@ public class ZippedAppFile implements Updatable {
} }
if (fname.endsWith (".hac")) { if (fname.endsWith (".hac")) {
String name = fname.substring (0, fname.lastIndexOf (".")); String name = fname.substring (0, fname.lastIndexOf ("."));
String sourceName = file.getName()+"/"+ename;
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
ActionFile act = new ActionFile (content, name, proto); ActionFile act = new ActionFile (content, name, sourceName, proto);
proto.actions.put (name, act); proto.addActionFile (act);
updatables.add (act); updatables.add (act);
// mark prototype as updated // mark prototype as updated
proto.markUpdated (); proto.markUpdated ();
} }
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 sourceName = file.getName()+"/"+ename;
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
Template tmp = new Template (content, name, proto); Template tmp = new Template (content, name, sourceName, proto);
proto.templates.put (name, tmp); proto.addTemplate (tmp);
updatables.add (tmp); updatables.add (tmp);
// mark prototype as updated // mark prototype as updated
proto.markUpdated (); proto.markUpdated ();
@ -95,21 +97,20 @@ public class ZippedAppFile implements Updatable {
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
SkinFile skin = new SkinFile (content, name, proto); SkinFile skin = new SkinFile (content, name, proto);
proto.skins.put (name, skin); proto.addSkinFile (skin);
updatables.add (skin); updatables.add (skin);
} }
else if (fname.endsWith (".js")) { else if (fname.endsWith (".js")) {
String name = fname.substring (0, fname.lastIndexOf (".")); String sourceName = file.getName()+"/"+ename;
String content = getZipEntryContent (zip, entry); String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]"); // System.err.println ("["+content+"]");
FunctionFile ff = new FunctionFile (content, name, proto); FunctionFile ff = new FunctionFile (content, sourceName, proto);
proto.functions.put (name, ff); proto.addFunctionFile (ff);
updatables.add (ff); updatables.add (ff);
// mark prototype as updated // mark prototype as updated
proto.markUpdated (); proto.markUpdated ();
} }
else if ("type.properties".equalsIgnoreCase (fname)) { else if ("type.properties".equalsIgnoreCase (fname)) {
String name = fname.substring (0, fname.lastIndexOf ("."));
DbMapping dbmap = proto.getDbMapping (); DbMapping dbmap = proto.getDbMapping ();
SystemProperties props = dbmap.getProperties (); SystemProperties props = dbmap.getProperties ();
props.addProps (file.getName(), zip.getInputStream (entry)); props.addProps (file.getName(), zip.getInputStream (entry));

View file

@ -21,8 +21,7 @@ import helma.util.Updatable;
public class ActionFile implements Updatable { public class ActionFile implements Updatable {
String name; String name, sourceName;
String functionName;
Prototype prototype; Prototype prototype;
Application app; Application app;
File file; File file;
@ -34,36 +33,21 @@ public class ActionFile implements Updatable {
this.prototype = proto; this.prototype = proto;
this.app = proto.getApplication (); this.app = proto.getApplication ();
this.name = name; this.name = name;
functionName = getName()+"_action"; this.sourceName = file.getParentFile().getName()+"/"+file.getName();
this.file = file; this.file = file;
this.content = null; this.content = null;
if (file != null)
update ();
} }
public ActionFile (String content, String name, Prototype proto) { public ActionFile (String content, String name, String sourceName, Prototype proto) {
this.prototype = proto; this.prototype = proto;
this.app = proto.getApplication (); this.app = proto.getApplication ();
this.name = name; this.name = name;
functionName = getName()+"_action"; this.sourceName = sourceName;
this.file = null; this.file = null;
this.content = content; 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 * Tell the type manager whether we need an update. this is the case when
* the file has been modified or deleted. * the file has been modified or deleted.
@ -74,41 +58,58 @@ public class ActionFile implements Updatable {
public void update () { public void update () {
if (!file.exists ()) { if (!file.exists ()) {
// remove functions declared by this from all object prototypes // remove functions declared by this from all object prototypes
remove (); remove ();
} else { } 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 (); lastmod = file.lastModified ();
} }
} }
public void remove () { public void remove () {
prototype.removeAction (name); prototype.removeActionFile (this);
if (file != null) }
prototype.removeUpdatable (file.getName());
public File getFile () {
return file;
} }
public String getName () { public String getName () {
return name; return name;
} }
public String getSourceName () {
return sourceName;
}
public Reader getReader () throws FileNotFoundException {
if (content != null)
return new StringReader (content);
else if (file.length() == 0)
return new StringReader(";");
else
return new FileReader (file);
}
public String getContent () { public String getContent () {
return content; if (content != null)
return content;
else {
try {
FileReader reader = new FileReader (file);
char cbuf[] = new char[(int) file.length ()];
reader.read (cbuf);
reader.close ();
return new String (cbuf);
} catch (Exception filex) {
app.logEvent ("Error reading "+this+": "+filex);
return null;
}
}
} }
public String getFunctionName () { public String getFunctionName () {
return functionName; return name + "_action";
} }
public Prototype getPrototype () { public Prototype getPrototype () {
@ -120,7 +121,7 @@ public class ActionFile implements Updatable {
} }
public String toString () { public String toString () {
return "ActionFile["+prototype.getName()+"/"+functionName+"]"; return "ActionFile["+sourceName+"]";
} }
} }

View file

@ -20,22 +20,18 @@ import helma.util.Updatable;
public class FunctionFile implements Updatable { public class FunctionFile implements Updatable {
String name;
Prototype prototype; Prototype prototype;
Application app; Application app;
File file; File file;
String sourceName;
String content; String content;
long lastmod; long lastmod;
// a set of funcion names defined by this file. We keep this to be able to
// remove them once the file should get removed
HashSet declaredProps;
long declaredPropsTimestamp;
public FunctionFile (File file, String name, Prototype proto) { public FunctionFile (File file, Prototype proto) {
this.prototype = proto; this.prototype = proto;
this.app = proto.getApplication (); this.app = proto.getApplication ();
this.name = name; this.sourceName = file.getParentFile().getName()+"/"+file.getName();
this.file = file; this.file = file;
update (); update ();
} }
@ -45,13 +41,12 @@ public class FunctionFile implements Updatable {
* 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 sourceName, Prototype proto) {
this.prototype = proto; this.prototype = proto;
this.app = proto.getApplication (); this.app = proto.getApplication ();
this.name = name; this.sourceName = sourceName;
this.file = null; this.file = null;
this.content = body; this.content = body;
update ();
} }
/** /**
@ -64,30 +59,15 @@ public class FunctionFile implements Updatable {
public void update () { public void update () {
if (file != null) { if (file != null) {
if (!file.exists ()) { if (!file.exists ()) {
remove (); remove ();
} else { } else {
lastmod = file.lastModified (); lastmod = file.lastModified ();
// app.typemgr.readFunctionFile (file, prototype.getName ());
// app.getScriptingEnvironment().evaluateFile (prototype, file);
} }
} else {
// app.getScriptingEnvironment().evaluateString (prototype, content);
} }
} }
/* public void evaluate (ScriptingEnvironment env) {
if (file != null)
env.evaluateFile (prototype, file);
else
env.evaluateString (prototype, content);
}*/
public boolean hasFile () {
return file != null;
}
public File getFile () { public File getFile () {
return file; return file;
} }
@ -96,19 +76,17 @@ public class FunctionFile implements Updatable {
return content; return content;
} }
public String getSourceName () {
return sourceName;
}
public void remove () { public void remove () {
prototype.removeFunctionFile (name); prototype.removeFunctionFile (this);
if (file != null)
prototype.removeUpdatable (file.getName());
} }
public String toString () { public String toString () {
if (file == null) return sourceName;
return "[Zipped script file]";
else
return prototype.getName()+"/"+file.getName();
} }

View file

@ -9,8 +9,6 @@ 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.Exceptions.*;
/** /**
@ -26,26 +24,36 @@ import helma.framework.core.*;
public class Template extends ActionFile { public class Template extends ActionFile {
String processedContent = null;
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) { public Template (String content, String name, String sourceName, Prototype proto) {
super (content, name, proto); super (content, name, sourceName, proto);
functionName = name;
} }
public String getFunctionName () {
return name;
}
public Reader getReader () {
return new StringReader(getContent());
}
public String getContent () { public String getContent () {
if (processedContent != null)
return processedContent;
Vector partBuffer = new Vector (); Vector partBuffer = new Vector ();
int l = content.length (); String cstring = super.getContent();
char[] cnt = cstring.toCharArray ();
int l = cnt.length;
if (l == 0) if (l == 0)
return ""; return "";
char cnt[] = new char[l];
content.getChars (0, l, cnt, 0);
// if last charackter is whitespace, swallow it. this is necessary for some inner templates to look ok. // if last charackter is whitespace, swallow it. this is necessary for some inner templates to look ok.
if (Character.isWhitespace (cnt[l-1])) if (Character.isWhitespace (cnt[l-1]))
@ -141,14 +149,12 @@ public class Template extends ActionFile {
} }
// templateBody.append ("\r\nreturn null;\r\n"); // templateBody.append ("\r\nreturn null;\r\n");
return templateBody.toString (); processedContent = templateBody.toString ();
return processedContent;
} }
public void remove () { public void remove () {
prototype.removeTemplate (name); prototype.removeTemplate (this);
if (file != null)
prototype.removeUpdatable (file.getName());
} }

View file

@ -29,30 +29,41 @@ public class FesiActionAdapter {
Prototype prototype; Prototype prototype;
Application app; Application app;
String functionName;
String sourceName; String sourceName;
// this is the parsed function which can be easily applied to RequestEvaluator objects // this is the parsed function which can be easily applied to FesiEvaluator objects
TypeUpdater pfunc, pfuncAsString; TypeUpdater pfunc, pfuncAsString;
public FesiActionAdapter (ActionFile action) { public FesiActionAdapter (ActionFile action) {
prototype = action.getPrototype (); prototype = action.getPrototype ();
app = action.getApplication (); app = action.getApplication ();
String content = action.getContent (); Reader reader = null;
String functionName = action.getFunctionName (); functionName = action.getFunctionName ();
sourceName = action.toString (); sourceName = action.getSourceName ();
try { try {
reader = action.getReader ();
pfunc = parseFunction (functionName, pfunc = parseFunction (functionName,
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
content); reader,
sourceName);
} catch (Throwable x) { } catch (Throwable x) {
String message = x.getMessage (); String message = x.getMessage ();
pfunc = new ErrorFeedback (functionName, message); pfunc = new ErrorFeedback (functionName, message);
} finally {
try {
reader.close();
} catch (Exception ignore) {}
} }
// check if this is a template and we need to generate an "_as_string" variant // check if this is a template and we need to generate an "_as_string" variant
if (action instanceof Template) { if (action instanceof Template) {
String content = "res.pushStringBuffer(); " +
action.getContent () +
"\r\nreturn res.popStringBuffer();\r\n";
try { try {
pfuncAsString = parseFunction (functionName+"_as_string", pfuncAsString = parseFunction (functionName+"_as_string",
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
"res.pushStringBuffer(); "+content+"\r\nreturn res.popStringBuffer();\r\n"); new StringReader(content),
sourceName);
} catch (Throwable x) { } catch (Throwable x) {
String message = x.getMessage (); String message = x.getMessage ();
pfunc = new ErrorFeedback (functionName+"_as_string", message); pfunc = new ErrorFeedback (functionName+"_as_string", message);
@ -70,7 +81,7 @@ public class FesiActionAdapter {
pfuncAsString.updateEvaluator (fesi); pfuncAsString.updateEvaluator (fesi);
} }
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException { protected TypeUpdater parseFunction (String funcName, String params, Reader body, String sourceName) throws EcmaScriptException {
// ESObject fp = app.eval.evaluator.getFunctionPrototype(); // ESObject fp = app.eval.evaluator.getFunctionPrototype();
// ConstructedFunctionObject function = null; // ConstructedFunctionObject function = null;
@ -78,15 +89,13 @@ public class FesiActionAdapter {
ASTStatementList sl = null; ASTStatementList sl = null;
FunctionEvaluationSource fes = null; FunctionEvaluationSource fes = null;
if (body == null || "".equals (body.trim())) /* if (body == null || "".equals (body.trim()))
body = ";\r\n"; body = ";\r\n";
else else
body = body + "\r\n"; body = body + "\r\n"; */
if (params == null) params = ""; if (params == null) params = "";
else params = params.trim (); else params = params.trim ();
String fulltext = "function "+funcname+" (" + params + ") {\n" + body + "\n}";
EcmaScript parser; EcmaScript parser;
StringReader is; StringReader is;
@ -100,26 +109,26 @@ public class FesiActionAdapter {
fpl = (ASTFormalParameterList) parser.FormalParameterList(); fpl = (ASTFormalParameterList) parser.FormalParameterList();
is.close(); is.close();
} catch (ParseException x) { } catch (ParseException x) {
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null)); throw new EcmaScriptParseException (x, new FileEvaluationSource(sourceName, null));
} }
} }
// this is very very very strange: without the toString, lots of obscure exceptions // this is very very very strange: without the toString, lots of obscure exceptions
// deep inside the parser... // deep inside the parser...
is = new java.io.StringReader(body.toString ()); // is = new java.io.StringReader(body.toString ());
try { try {
parser = new EcmaScript (is); parser = new EcmaScript (body);
sl = (ASTStatementList) parser.StatementList(); sl = (ASTStatementList) parser.StatementList();
is.close(); body.close();
} catch (ParseException x) { } catch (ParseException x) {
app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x); app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null)); throw new EcmaScriptParseException (x, new FileEvaluationSource(sourceName, null));
} catch (Exception x) { } catch (Exception x) {
app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x); app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
throw new RuntimeException (x.getMessage ()); throw new RuntimeException (x.getMessage ());
} }
fes = new FunctionEvaluationSource (new StringEvaluationSource(fulltext, null), funcname); fes = new FunctionEvaluationSource (new FileEvaluationSource(sourceName, null), funcName);
return new ParsedFunction (fpl, sl, fes, fulltext, funcname); return new ParsedFunction (fpl, sl, fes, null, funcName);
} }
class ParsedFunction implements TypeUpdater { class ParsedFunction implements TypeUpdater {

View file

@ -112,7 +112,7 @@ public final class FesiEvaluator implements ScriptingEngine {
} }
/** /**
* Initialize the evaluator, making sure the minimum type information * Initialize the evaluator, making sure the minimum type information
* necessary to bootstrap the rest is parsed. * necessary to bootstrap the rest is parsed.
*/ */
private void initialize () { private void initialize () {
@ -127,7 +127,7 @@ public final class FesiEvaluator implements ScriptingEngine {
getPrototype ("global"); getPrototype ("global");
} }
/** /**
* Initialize a prototype without fully parsing its script files. * Initialize a prototype without fully parsing its script files.
*/ */
void initPrototype (Prototype prototype) { void initPrototype (Prototype prototype) {
@ -146,7 +146,10 @@ public final class FesiEvaluator implements ScriptingEngine {
} }
} }
String name = prototype.getName (); String name = prototype.getName ();
if (!"global".equalsIgnoreCase (name) && !"hopobject".equalsIgnoreCase (name) && opp == null) { if (!"global".equalsIgnoreCase (name) &&
!"hopobject".equalsIgnoreCase (name) &&
opp == null)
{
if (app.isJavaPrototype (name)) if (app.isJavaPrototype (name))
opp = getRawPrototype ("__javaobject__"); opp = getRawPrototype ("__javaobject__");
else else
@ -228,26 +231,13 @@ public final class FesiEvaluator implements ScriptingEngine {
global.putHiddenProperty (name, new NodeConstructor (name, fp, this)); global.putHiddenProperty (name, new NodeConstructor (name, fp, this));
} catch (EcmaScriptException ignore) {} } catch (EcmaScriptException ignore) {}
} }
for (Iterator it = prototype.getFunctions().values().iterator(); it.hasNext(); ) { for (Iterator it = prototype.getZippedCode().values().iterator(); it.hasNext(); ) {
FunctionFile ff = (FunctionFile) it.next (); Object code = it.next();
if (ff.hasFile ()) evaluate (prototype, code);
evaluateFile (prototype, ff.getFile ());
else
evaluateString (prototype, ff.getContent ());
} }
for (Iterator it = prototype.getTemplates().values().iterator(); it.hasNext(); ) { for (Iterator it = prototype.getCode().values().iterator(); it.hasNext(); ) {
Template tmp = (Template) it.next (); Object code = it.next();
try { evaluate (prototype, code);
FesiActionAdapter adp = new FesiActionAdapter (tmp);
adp.updateEvaluator (this);
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = prototype.getActions().values().iterator(); it.hasNext(); ) {
ActionFile act = (ActionFile) it.next ();
try {
FesiActionAdapter adp = new FesiActionAdapter (act);
adp.updateEvaluator (this);
} catch (EcmaScriptException ignore) {}
} }
} }
@ -665,6 +655,8 @@ public final class FesiEvaluator implements ScriptingEngine {
public ESValue getObjectWrapper (Object e) { public ESValue getObjectWrapper (Object e) {
if (app.getPrototypeName (e) != null) if (app.getPrototypeName (e) != null)
return getElementWrapper (e); return getElementWrapper (e);
/* else if (e instanceof Map)
return new ESMapWrapper (this, (Map) e); */
/* else if (e instanceof INode) /* else if (e instanceof INode)
return new ESNode ((INode) e, this); */ return new ESNode ((INode) e, this); */
else else
@ -762,21 +754,34 @@ public final class FesiEvaluator implements ScriptingEngine {
return reval.req; return reval.req;
} }
public synchronized void evaluateFile (Prototype prototype, File file) { private synchronized void evaluate (Prototype prototype, Object code) {
try { if (code instanceof FunctionFile) {
FileReader fr = new FileReader (file); FunctionFile funcfile = (FunctionFile) code;
EvaluationSource es = new FileEvaluationSource (file.getPath (), null); File file = funcfile.getFile ();
updateEvaluator (prototype, fr, es); if (file != null) {
} catch (IOException iox) { try {
app.logEvent ("Error updating function file: "+iox); FileReader fr = new FileReader (file);
EvaluationSource es = new FileEvaluationSource (funcfile.getSourceName(), null);
updateEvaluator (prototype, fr, es);
} catch (IOException iox) {
app.logEvent ("Error updating function file: "+iox);
}
} else {
StringReader reader = new StringReader (funcfile.getContent());
EvaluationSource es = new FileEvaluationSource (funcfile.getSourceName(), null);
updateEvaluator (prototype, reader, es);
}
} else if (code instanceof ActionFile) {
ActionFile action = (ActionFile) code;
FesiActionAdapter fa = new FesiActionAdapter (action);
try {
fa.updateEvaluator (this);
} catch (EcmaScriptException esx) {
app.logEvent ("Error parsing "+action+": "+esx);
}
} }
} }
public synchronized void evaluateString (Prototype prototype, String code) {
StringReader reader = new StringReader (code);
StringEvaluationSource es = new StringEvaluationSource (code, null);
updateEvaluator (prototype, reader, es);
}
private synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) { private synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) {
try { try {