Get prototype resources through synchronized methods instead of directly

accessing them. This fixes a bug where prototypes that were in the process of
being compiled were accessed by evaluators.

Pass through RedirectException if notModified() has been called on the response
object.
This commit is contained in:
hns 2002-08-02 13:32:56 +00:00
parent 6182b9313a
commit a1080de978
5 changed files with 90 additions and 18 deletions

View file

@ -3,6 +3,7 @@
package helma.framework.core;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.*;
@ -25,11 +26,11 @@ public final class Prototype {
final String name;
final Application app;
public final HashMap templates;
public final HashMap functions;
public final HashMap actions;
public final HashMap skins;
public final HashMap updatables;
final HashMap templates;
final HashMap functions;
final HashMap actions;
final HashMap skins;
final HashMap updatables;
// lastCheck is the time the prototype's files were last checked
private long lastCheck;
@ -181,6 +182,62 @@ public final class Prototype {
lastCheck = System.currentTimeMillis ();
}
/**
* Return a clone of this prototype's actions container. Synchronized
* to not return a map in a transient state where it is just being
* updated by the type manager.
*/
public synchronized Map getActions () {
return (Map) actions.clone();
}
/**
* Return a clone of this prototype's functions container. Synchronized
* to not return a map in a transient state where it is just being
* updated by the type manager.
*/
public synchronized Map getFunctions () {
return (Map) functions.clone();
}
/**
* Return a clone of this prototype's templates container. Synchronized
* to not return a map in a transient state where it is just being
* updated by the type manager.
*/
public synchronized Map getTemplates () {
return (Map) templates.clone();
}
/**
* Return a clone of this prototype's skins container. Synchronized
* to not return a map in a transient state where it is just being
* updated by the type manager.
*/
public synchronized Map getSkins () {
return (Map) skins.clone();
}
public synchronized void removeUpdatable (String fileName) {
updatables.remove (fileName);
}
public synchronized void removeAction (String actionName) {
actions.remove (actionName);
}
public synchronized void removeFunctionFile (String functionFileName) {
functions.remove (functionFileName);
}
public synchronized void removeTemplate (String templateName) {
templates.remove (templateName);
}
/**
* Return a string representing this prototype.
*/
public String toString () {
return "[Prototype "+ app.getName()+"/"+name+"]";
}

View file

@ -94,9 +94,9 @@ public class ActionFile implements Updatable {
}
protected void remove () {
prototype.actions.remove (name);
prototype.removeAction (name);
if (file != null)
prototype.updatables.remove (file.getName());
prototype.removeUpdatable (file.getName());
}
public String getName () {

View file

@ -98,8 +98,8 @@ public class FunctionFile implements Updatable {
void remove () {
prototype.functions.remove (name);
prototype.updatables.remove (file.getName());
prototype.removeFunctionFile (name);
prototype.removeUpdatable (file.getName());
// if we did not add anything to any evaluator, we're done
/* if (declaredProps == null || declaredProps.size() == 0)

View file

@ -176,9 +176,9 @@ public class Template extends ActionFile {
}
protected void remove () {
prototype.templates.remove (name);
prototype.removeTemplate (name);
if (file != null)
prototype.updatables.remove (file.getName());
prototype.removeUpdatable (file.getName());
/* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) {

View file

@ -24,7 +24,6 @@ import Acme.LruHashtable;
/**
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
*/
public final class FesiEvaluator implements ScriptingEngine {
// the application we're running in
@ -63,6 +62,9 @@ public final class FesiEvaluator implements ScriptingEngine {
// the global vars set by extensions
HashMap extensionGlobals;
/**
* Create a FESI evaluator for the given application and request evaluator.
*/
public FesiEvaluator (Application app, RequestEvaluator reval) {
this.app = app;
this.reval = reval;
@ -108,6 +110,10 @@ public final class FesiEvaluator implements ScriptingEngine {
}
}
/**
* Initialize the evaluator, making sure the minimum type information
* necessary to bootstrap the rest is parsed.
*/
private void initialize () {
Collection prototypes = app.getPrototypes();
for (Iterator i=prototypes.iterator(); i.hasNext(); ) {
@ -120,6 +126,9 @@ public final class FesiEvaluator implements ScriptingEngine {
getPrototype ("global");
}
/**
* Initialize a prototype without fully parsing its script files.
*/
void initPrototype (Prototype prototype) {
// System.err.println ("FESI INIT PROTO "+prototype);
ObjectPrototype op = null;
@ -169,6 +178,9 @@ public final class FesiEvaluator implements ScriptingEngine {
// evaluatePrototype (prototype);
}
/**
* Set up a prototype, parsing and compiling all its script files.
*/
void evaluatePrototype (Prototype prototype) {
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
ObjectPrototype op = null;
@ -215,21 +227,21 @@ public final class FesiEvaluator implements ScriptingEngine {
global.putHiddenProperty (name, new NodeConstructor (name, fp, this));
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = prototype.functions.values().iterator(); it.hasNext(); ) {
for (Iterator it = prototype.getFunctions().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(); ) {
for (Iterator it = prototype.getTemplates().values().iterator(); it.hasNext(); ) {
Template tmp = (Template) it.next ();
try {
FesiActionAdapter adp = new FesiActionAdapter (tmp);
adp.updateEvaluator (this);
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = prototype.actions.values().iterator(); it.hasNext(); ) {
for (Iterator it = prototype.getActions().values().iterator(); it.hasNext(); ) {
ActionFile act = (ActionFile) it.next ();
try {
FesiActionAdapter adp = new FesiActionAdapter (act);
@ -380,6 +392,9 @@ public final class FesiEvaluator implements ScriptingEngine {
// into an EcmaScript exception, which is why we can't explicitly catch it
if (reval.res.getRedirect() != null)
throw new RedirectException (reval.res.getRedirect ());
// do the same for not-modified responses
if (reval.res.getNotModified())
throw new RedirectException (null);
// create and throw a ScriptingException with the right message
String msg = x.getMessage ();
if (msg == null || msg.length() < 10)