merged in changes from "lazy_typing" branch, prototypes
are only initialized on demand.
This commit is contained in:
		
							parent
							
								
									f1a304f122
								
							
						
					
					
						commit
						aa4c0389d4
					
				
					 10 changed files with 460 additions and 461 deletions
				
			
		|  | @ -25,16 +25,13 @@ import java.rmi.server.*; | ||||||
|  * requests from the Web server or XML-RPC port and dispatches them to |  * requests from the Web server or XML-RPC port and dispatches them to | ||||||
|  * the evaluators. |  * the evaluators. | ||||||
|  */ |  */ | ||||||
| public class Application extends UnicastRemoteObject implements IRemoteApp, IPathElement, IReplicatedApp, Runnable { | public final class Application extends UnicastRemoteObject implements IRemoteApp, IPathElement, IReplicatedApp, Runnable { | ||||||
| 
 | 
 | ||||||
|     private String name; |     private String name; | ||||||
|     SystemProperties props, dbProps; |     SystemProperties props, dbProps; | ||||||
|     File home, appDir, dbDir; |     File home, appDir, dbDir; | ||||||
|     protected NodeManager nmgr; |     protected NodeManager nmgr; | ||||||
| 
 | 
 | ||||||
|     // the class name of the scripting environment implementation |  | ||||||
|     ScriptingEnvironment scriptingEngine; |  | ||||||
| 
 |  | ||||||
|     // 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. | ||||||
|     Object rootObject = null; |     Object rootObject = null; | ||||||
|  | @ -111,9 +108,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
|     // Map of extensions allowed for public skins |     // Map of extensions allowed for public skins | ||||||
|     Properties skinExtensions; |     Properties skinExtensions; | ||||||
| 
 | 
 | ||||||
|     // a cache for parsed skin objects |  | ||||||
|     public CacheMap skincache = new CacheMap (200, 0.80f); |  | ||||||
| 
 |  | ||||||
|     // DocApplication used for introspection |     // DocApplication used for introspection | ||||||
|     public DocApplication docApp; |     public DocApplication docApp; | ||||||
| 
 | 
 | ||||||
|  | @ -228,29 +222,29 @@ 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 DatabaseException, ScriptingException { |     public void init () throws DatabaseException, ScriptingException { | ||||||
| 	scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment (); | 	// scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment (); | ||||||
| 	scriptingEngine.init (this, props); | 	// scriptingEngine.init (this, props); | ||||||
| 
 |  | ||||||
| 	eval = new RequestEvaluator (this); |  | ||||||
| 	logEvent ("Starting evaluators for "+name); |  | ||||||
| 	int maxThreads = 12; |  | ||||||
| 	try { |  | ||||||
| 	    maxThreads = Integer.parseInt (props.getProperty ("maxThreads")); |  | ||||||
| 	} catch (Exception ignore) {} |  | ||||||
| 	freeThreads = new Stack (); |  | ||||||
| 	allThreads = new Vector (); |  | ||||||
| 	allThreads.addElement (eval); |  | ||||||
| 	for (int i=0; i<maxThreads; i++) { |  | ||||||
| 	    RequestEvaluator ev = new RequestEvaluator (this); |  | ||||||
| 	    freeThreads.push (ev); |  | ||||||
| 	    allThreads.addElement (ev); |  | ||||||
| 	} |  | ||||||
| 	activeRequests = new Hashtable (); |  | ||||||
| 
 | 
 | ||||||
| 	typemgr = new TypeManager (this); | 	typemgr = new TypeManager (this); | ||||||
| 	typemgr.createPrototypes (); | 	typemgr.createPrototypes (); | ||||||
| 	// logEvent ("Started type manager for "+name); | 	// logEvent ("Started type manager for "+name); | ||||||
| 
 | 
 | ||||||
|  | 	// eval = new RequestEvaluator (this); | ||||||
|  | 	logEvent ("Starting evaluators for "+name); | ||||||
|  | 	freeThreads = new Stack (); | ||||||
|  | 	allThreads = new Vector (); | ||||||
|  | 	// allThreads.addElement (eval); | ||||||
|  | 	/* int maxThreads = 12; | ||||||
|  | 	try { | ||||||
|  | 	    maxThreads = Integer.parseInt (props.getProperty ("maxThreads")); | ||||||
|  | 	} catch (Exception ignore) {} | ||||||
|  | 	for (int i=0; i<maxThreads; i++) { | ||||||
|  | 	    RequestEvaluator ev = new RequestEvaluator (this); | ||||||
|  | 	    freeThreads.push (ev); | ||||||
|  | 	    allThreads.addElement (ev); | ||||||
|  | 	} */ | ||||||
|  | 	activeRequests = new Hashtable (); | ||||||
|  | 
 | ||||||
| 	skinmgr = new SkinManager (this); | 	skinmgr = new SkinManager (this); | ||||||
| 
 | 
 | ||||||
| 	rootMapping = getDbMapping ("root"); | 	rootMapping = getDbMapping ("root"); | ||||||
|  | @ -272,11 +266,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	if (xmlrpc != null) | 	if (xmlrpc != null) | ||||||
| 	    xmlrpc.addHandler (xmlrpcHandlerName, new XmlRpcInvoker (this)); | 	    xmlrpc.addHandler (xmlrpcHandlerName, new XmlRpcInvoker (this)); | ||||||
| 
 | 
 | ||||||
| 	// typemgr.start (); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      *  Create request evaluators and start scheduler and cleanup thread |      *  Create and start scheduler and cleanup thread | ||||||
|      */ |      */ | ||||||
|     public void start () { |     public void start () { | ||||||
| 	starttime = System.currentTimeMillis(); | 	starttime = System.currentTimeMillis(); | ||||||
|  | @ -320,6 +313,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	    System.err.println ("Error shutting down embedded db: "+dbx); | 	    System.err.println ("Error shutting down embedded db: "+dbx); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// null out type manager | ||||||
|  | 	typemgr = null; | ||||||
|  | 
 | ||||||
| 	// stop logs if they exist | 	// stop logs if they exist | ||||||
| 	if (eventLog != null) { | 	if (eventLog != null) { | ||||||
| 	    eventLog.close (); | 	    eventLog.close (); | ||||||
|  | @ -339,6 +335,20 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	try { | 	try { | ||||||
| 	    return (RequestEvaluator) freeThreads.pop (); | 	    return (RequestEvaluator) freeThreads.pop (); | ||||||
| 	} catch (EmptyStackException nothreads) { | 	} catch (EmptyStackException nothreads) { | ||||||
|  | 	    synchronized (this) { | ||||||
|  | 	        int maxThreads = 12; | ||||||
|  | 	        try { | ||||||
|  | 	            maxThreads = Integer.parseInt (props.getProperty ("maxThreads")); | ||||||
|  | 	        } catch (Exception ignore) { | ||||||
|  | 	            // property not set, use default value | ||||||
|  | 	        } | ||||||
|  | 	        if (allThreads.size() < maxThreads) { | ||||||
|  | 	            logEvent ("Starting evaluator "+(allThreads.size()+1) +" for application "+name); | ||||||
|  | 	            RequestEvaluator ev = new RequestEvaluator (this); | ||||||
|  | 	            allThreads.addElement (ev); | ||||||
|  | 	            return (ev); | ||||||
|  | 	        } | ||||||
|  | 	    } | ||||||
| 	    throw new RuntimeException ("Maximum Thread count reached."); | 	    throw new RuntimeException ("Maximum Thread count reached."); | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|  | @ -347,8 +357,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
|      * Returns an evaluator back to the pool when the work is done. |      * Returns an evaluator back to the pool when the work is done. | ||||||
|      */ |      */ | ||||||
|     protected void releaseEvaluator (RequestEvaluator ev) { |     protected void releaseEvaluator (RequestEvaluator ev) { | ||||||
| 	if (ev != null) |         if (ev != null) { | ||||||
| 	    freeThreads.push (ev); |             ev.recycle (); | ||||||
|  |             freeThreads.push (ev); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -435,6 +447,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	        // response needs to be closed/encoded before sending it back | 	        // response needs to be closed/encoded before sending it back | ||||||
| 	        try { | 	        try { | ||||||
| 	            res.close (charset); | 	            res.close (charset); | ||||||
|  | 	            // reset data fields for garbage collection (may hold references to evaluator) | ||||||
|  | 	            res.data = null; | ||||||
|  | 	            req.data = null; | ||||||
| 	        } catch (UnsupportedEncodingException uee) { | 	        } catch (UnsupportedEncodingException uee) { | ||||||
| 	            logEvent ("Unsupported response encoding: "+uee.getMessage()); | 	            logEvent ("Unsupported response encoding: "+uee.getMessage()); | ||||||
| 	        } | 	        } | ||||||
|  | @ -442,7 +457,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	        res.waitForClose (); | 	        res.waitForClose (); | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return res; | 	return res; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -845,6 +859,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	return debug; | 	return debug; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      *  Utiliti function invoker for the methods below. This *must* be called  | ||||||
|  |      *  by an active RequestEvaluator thread. | ||||||
|  |      */ | ||||||
|     private Object invokeFunction (Object obj, String func, Object[] args) { |     private Object invokeFunction (Object obj, String func, Object[] args) { | ||||||
| 	Thread thread = Thread.currentThread (); | 	Thread thread = Thread.currentThread (); | ||||||
| 	RequestEvaluator reval = null; | 	RequestEvaluator reval = null; | ||||||
|  | @ -858,13 +876,13 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	    return reval.invokeDirectFunction (obj, func, args); | 	    return reval.invokeDirectFunction (obj, func, args); | ||||||
| 	} catch (Exception x) { | 	} catch (Exception x) { | ||||||
| 	    if (debug) | 	    if (debug) | ||||||
| 	        System.err.println ("ERROR invoking function "+func+": "+x); | 	        System.err.println ("Error in Application.invokeFunction ("+func+"): "+x); | ||||||
| 	} | 	} | ||||||
| 	return null; | 	return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////////////// |     ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|     ///   The following methods mimic the IPathElement interface. This allows as |     ///   The following methods mimic the IPathElement interface. This allows us | ||||||
|     ///   to script any Java object: If the object implements IPathElement (as does |     ///   to script any Java object: If the object implements IPathElement (as does | ||||||
|     ///   the Node class in Helma's internal objectmodel) then the corresponding |     ///   the Node class in Helma's internal objectmodel) then the corresponding | ||||||
|     ///   method is called in the object itself. Otherwise, a corresponding script function |     ///   method is called in the object itself. Otherwise, a corresponding script function | ||||||
|  | @ -999,14 +1017,6 @@ 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. | ||||||
|  | @ -1014,12 +1024,19 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
|     public void run () { |     public void run () { | ||||||
| 	long cleanupSleep = 60000;    // thread sleep interval (fixed) | 	long cleanupSleep = 60000;    // thread sleep interval (fixed) | ||||||
| 	long scheduleSleep = 60000;  // interval for scheduler invocation | 	long scheduleSleep = 60000;  // interval for scheduler invocation | ||||||
| 	long lastScheduler = 0; | 	long lastScheduler = 0;    // run scheduler immediately | ||||||
| 	long lastCleanup = System.currentTimeMillis (); | 	long lastCleanup = System.currentTimeMillis (); | ||||||
| 
 | 
 | ||||||
| 	// logEvent ("Starting scheduler for "+name); | 	// logEvent ("Starting scheduler for "+name); | ||||||
| 	// as first thing, invoke function onStart in the root object | 	// as first thing, invoke function onStart in the root object | ||||||
| 
 | 
 | ||||||
|  | 	eval = new RequestEvaluator (this); | ||||||
|  | 	allThreads.addElement (eval); | ||||||
|  | 
 | ||||||
|  | 	// read in standard prototypes to make first request go faster | ||||||
|  | 	typemgr.updatePrototype ("root"); | ||||||
|  | 	typemgr.updatePrototype ("global"); | ||||||
|  | 
 | ||||||
| 	try { | 	try { | ||||||
| 	    eval.invokeFunction ((INode) null, "onStart", new Object[0]); | 	    eval.invokeFunction ((INode) null, "onStart", new Object[0]); | ||||||
| 	} catch (Exception ignore) { | 	} catch (Exception ignore) { | ||||||
|  | @ -1032,8 +1049,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	    try { | 	    try { | ||||||
| 	        sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30"))); | 	        sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30"))); | ||||||
| 	    } catch (Exception ignore) { | 	    } catch (Exception ignore) { | ||||||
| 	    	System.out.println(ignore.toString()); | 	        System.out.println(ignore.toString()); | ||||||
| 	    	} | 	    } | ||||||
| 
 | 
 | ||||||
| 	    long now = System.currentTimeMillis (); | 	    long now = System.currentTimeMillis (); | ||||||
| 
 | 
 | ||||||
|  | @ -1044,9 +1061,12 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	        for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) { | 	        for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) { | ||||||
| 	            Session session = (Session) e.nextElement (); | 	            Session session = (Session) e.nextElement (); | ||||||
| 	            if (now - session.lastTouched () > sessionTimeout * 60000) { | 	            if (now - session.lastTouched () > sessionTimeout * 60000) { | ||||||
| //	                if (session.uid != null) { | 	                INode usernode = session.getUserNode (); | ||||||
| //	FIXME onlogout()!        try {eval.invokeFunction (u, "onLogout", new Object[0]);} catch (Exception ignore) {} | 	                if (usernode != null) { | ||||||
| //	                } | 	                    try { | ||||||
|  | 	                        eval.invokeFunction (usernode, "onLogout", new Object[0]); | ||||||
|  | 	                    } catch (Exception ignore) {} | ||||||
|  | 	                } | ||||||
| 	                destroySession(session); | 	                destroySession(session); | ||||||
| 	            } | 	            } | ||||||
| 	        } | 	        } | ||||||
|  | @ -1080,10 +1100,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat | ||||||
| 	        worker = null; | 	        worker = null; | ||||||
| 	        break; | 	        break; | ||||||
| 	    } | 	    } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	logEvent ("Scheduler for "+name+" exiting"); | 	logEvent ("Scheduler for "+name+" exiting"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,22 +13,22 @@ import helma.util.Updatable; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The Prototype class represents JavaScript prototypes defined in HOP |  * The Prototype class represents Script prototypes/type defined in a Helma | ||||||
|  * applications. This manages a prototypes templates, functions and actions  |  * application. This class manages a prototypes templates, functions and actions  | ||||||
|  * as well as optional information about the mapping of this type to a  |  * as well as optional information about the mapping of this type to a  | ||||||
|  * relational database table. |  * relational database table. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| public class Prototype { | public final class Prototype { | ||||||
| 
 | 
 | ||||||
|     String id; |     String id; | ||||||
|     String name; |     String name; | ||||||
|     Application app; |     Application app; | ||||||
|     public HashMap templates, functions, actions, skins, updatables; |     public HashMap templates, functions, actions, skins, updatables; | ||||||
|     long lastUpdate; |     long lastUpdate, lastCheck; | ||||||
| 
 | 
 | ||||||
|     Prototype parent; |     private Prototype parent; | ||||||
| 
 | 
 | ||||||
|     // Tells us whether this prototype is used to script a generic Java object, |     // Tells us whether this prototype is used to script a generic Java object, | ||||||
|     // as opposed to a Helma objectmodel node object. |     // as opposed to a Helma objectmodel node object. | ||||||
|  | @ -39,7 +39,7 @@ public class Prototype { | ||||||
| 	this.app = app; | 	this.app = app; | ||||||
| 	this.name = name; | 	this.name = name; | ||||||
| 	isJavaPrototype = app.isJavaPrototype (name); | 	isJavaPrototype = app.isJavaPrototype (name); | ||||||
| 	lastUpdate = 0; // System.currentTimeMillis (); | 	lastUpdate = lastCheck = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -57,29 +57,7 @@ public class Prototype { | ||||||
| 	// this is not allowed for the hopobject and global prototypes | 	// this is not allowed for the hopobject and global prototypes | ||||||
| 	if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name)) | 	if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name)) | ||||||
| 	    return; | 	    return; | ||||||
| 	     |  | ||||||
| 	Prototype old = this.parent; |  | ||||||
| 	this.parent = parent; | 	this.parent = parent; | ||||||
| 
 |  | ||||||
| 	// if parent has changed, update ES-prototypes in request evaluators |  | ||||||
| 	if (parent != old) { |  | ||||||
| 	    /* Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); |  | ||||||
| 	    while (evals.hasNext ()) { |  | ||||||
| 	        try { |  | ||||||
| 	            RequestEvaluator reval = (RequestEvaluator) evals.next (); |  | ||||||
| 	            ObjectPrototype op = reval.getPrototype (getName()); |  | ||||||
| 	            // use hopobject (node) as prototype even if prototype is null - |  | ||||||
| 	            // this is the case if no hopobject directory exists |  | ||||||
| 	            ObjectPrototype opp = parent == null ? |  | ||||||
| 	            	reval.esNodePrototype : reval.getPrototype (parent.getName ()); |  | ||||||
| 	            // don't think this is possible, but check anyway |  | ||||||
| 	            if (opp == null) |  | ||||||
| 	                opp = reval.esNodePrototype; |  | ||||||
| 	            op.setPrototype (opp); |  | ||||||
| 	        } catch (Exception ignore) { |  | ||||||
| 	        } |  | ||||||
| 	    } */ |  | ||||||
| 	} |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public Prototype getParentPrototype () { |     public Prototype getParentPrototype () { | ||||||
|  | @ -125,10 +103,23 @@ public class Prototype { | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
| 	return upd; | 	return upd; | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public long getLastUpdate () { | ||||||
|  | 	return lastUpdate; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     public void markUpdated () { | ||||||
|  | 	lastUpdate = System.currentTimeMillis (); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public long getLastCheck () { | ||||||
|  | 	return lastCheck; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void markChecked () { | ||||||
|  | 	lastCheck = System.currentTimeMillis (); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     public String toString () { |     public String toString () { | ||||||
| 	return "[Prototype "+ app.getName()+"/"+name+"]"; | 	return "[Prototype "+ app.getName()+"/"+name+"]"; | ||||||
|  |  | ||||||
|  | @ -18,11 +18,12 @@ import java.util.*; | ||||||
|  * is killed and an error message is returned. |  * is killed and an error message is returned. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| public class RequestEvaluator implements Runnable { | public final class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     public Application app; |     public final Application app; | ||||||
|     protected boolean initialized; | 
 | ||||||
|  |     protected final ScriptingEngine scriptingEngine; | ||||||
| 
 | 
 | ||||||
|     public RequestTrans req; |     public RequestTrans req; | ||||||
|     public ResponseTrans res; |     public ResponseTrans res; | ||||||
|  | @ -44,7 +45,7 @@ public class RequestEvaluator implements Runnable { | ||||||
|     // the object path of the request we're evaluating |     // the object path of the request we're evaluating | ||||||
|     List requestPath; |     List requestPath; | ||||||
| 
 | 
 | ||||||
|     // the result of the |     // the result of the operation | ||||||
|     Object result; |     Object result; | ||||||
| 
 | 
 | ||||||
|     // the exception thrown by the evaluator, if any. |     // the exception thrown by the evaluator, if any. | ||||||
|  | @ -63,7 +64,7 @@ public class RequestEvaluator implements Runnable { | ||||||
|      */ |      */ | ||||||
|     public RequestEvaluator (Application app) { |     public RequestEvaluator (Application app) { | ||||||
| 	this.app = app; | 	this.app = app; | ||||||
| 	initialized = false; | 	scriptingEngine = helma.scripting.fesi.FesiEngineFactory.getEngine (app, this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -79,9 +80,6 @@ public class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 	    // long startCheck = System.currentTimeMillis (); | 	    // long startCheck = System.currentTimeMillis (); | ||||||
| 	    app.typemgr.checkPrototypes (); | 	    app.typemgr.checkPrototypes (); | ||||||
| 	    // evaluators are only initialized as needed, so we need to check that here |  | ||||||
| 	    // if (!initialized) |  | ||||||
| 	    //     app.typemgr.initRequestEvaluator (this); |  | ||||||
| 	    // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis"); | 	    // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis"); | ||||||
| 
 | 
 | ||||||
| 	    // object refs to ressolve request path | 	    // object refs to ressolve request path | ||||||
|  | @ -225,13 +223,16 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	                try { | 	                try { | ||||||
| 	                    localrtx.timer.beginEvent (txname+" execute"); | 	                    localrtx.timer.beginEvent (txname+" execute"); | ||||||
| 
 | 
 | ||||||
|  | 	                    // enter execution context | ||||||
|  | 	                    scriptingEngine.enterContext (globals); | ||||||
|  | 
 | ||||||
| 	                    // set the req.action property, cutting off the _action suffix | 	                    // set the req.action property, cutting off the _action suffix | ||||||
| 	                    req.action = action.substring (0, action.length()-7); | 	                    req.action = action.substring (0, action.length()-7); | ||||||
| 
 | 
 | ||||||
| 	                    // try calling onRequest() function on object before | 	                    // try calling onRequest() function on object before | ||||||
| 	                    // calling the actual action | 	                    // calling the actual action | ||||||
| 	                    try { | 	                    try { | ||||||
| 	                        app.scriptingEngine.invoke (currentElement, "onRequest", new Object[0], globals, this); | 	                        scriptingEngine.invoke (currentElement, "onRequest", new Object[0]); | ||||||
| 	                    } catch (RedirectException redir) { | 	                    } catch (RedirectException redir) { | ||||||
| 	                        throw redir; | 	                        throw redir; | ||||||
| 	                    } catch (Exception ignore) { | 	                    } catch (Exception ignore) { | ||||||
|  | @ -239,7 +240,7 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	                    } | 	                    } | ||||||
| 
 | 
 | ||||||
| 	                    // do the actual action invocation | 	                    // do the actual action invocation | ||||||
| 	                    app.scriptingEngine.invoke (currentElement, action, new Object[0], globals, this); | 	                    scriptingEngine.invoke (currentElement, action, new Object[0]); | ||||||
| 
 | 
 | ||||||
| 	                    localrtx.timer.endEvent (txname+" execute"); | 	                    localrtx.timer.endEvent (txname+" execute"); | ||||||
| 	                } catch (RedirectException redirect) { | 	                } catch (RedirectException redirect) { | ||||||
|  | @ -324,6 +325,8 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	            globals.put ("res", res); | 	            globals.put ("res", res); | ||||||
| 	            globals.put ("app", app); | 	            globals.put ("app", app); | ||||||
| 
 | 
 | ||||||
|  | 	            scriptingEngine.enterContext (globals); | ||||||
|  | 
 | ||||||
| 	            currentElement = root; | 	            currentElement = root; | ||||||
| 
 | 
 | ||||||
| 	            if (method.indexOf (".") > -1) { | 	            if (method.indexOf (".") > -1) { | ||||||
|  | @ -343,7 +346,7 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	            String proto = app.getPrototypeName (currentElement); | 	            String proto = app.getPrototypeName (currentElement); | ||||||
| 	            app.checkXmlRpcAccess (proto, method); | 	            app.checkXmlRpcAccess (proto, method); | ||||||
| 
 | 
 | ||||||
| 	            result = app.scriptingEngine.invoke (currentElement, method, args, globals, this); | 	            result = scriptingEngine.invoke (currentElement, method, args); | ||||||
| 	            commitTransaction (); | 	            commitTransaction (); | ||||||
| 
 | 
 | ||||||
| 	        } catch (Exception wrong) { | 	        } catch (Exception wrong) { | ||||||
|  | @ -366,14 +369,12 @@ public class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 	        // avoid going into transaction if called function doesn't exist | 	        // avoid going into transaction if called function doesn't exist | ||||||
| 	        boolean functionexists = true; | 	        boolean functionexists = true; | ||||||
| 	        if (thisObject == null) try { | 	        functionexists = scriptingEngine.hasFunction (thisObject, method); | ||||||
| 	            functionexists = app.scriptingEngine.hasFunction (null, method, this); |  | ||||||
| 			} catch (ScriptingException ignore) {} |  | ||||||
| 
 | 
 | ||||||
| 	        if (!functionexists) | 	        if (!functionexists) { | ||||||
| 	            // global function doesn't exist, nothing to do here. | 	            // function doesn't exist, nothing to do here. | ||||||
| 	            reqtype = NONE; | 	            reqtype = NONE; | ||||||
| 	        else try { | 	        } else try { | ||||||
| 	            localrtx.begin (funcdesc); | 	            localrtx.begin (funcdesc); | ||||||
| 
 | 
 | ||||||
| 	            root = app.getDataRoot (); | 	            root = app.getDataRoot (); | ||||||
|  | @ -383,7 +384,9 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	            globals.put ("res", res); | 	            globals.put ("res", res); | ||||||
| 	            globals.put ("app", app); | 	            globals.put ("app", app); | ||||||
| 
 | 
 | ||||||
| 	            app.scriptingEngine.invoke (thisObject, method, args, globals, this); | 	            scriptingEngine.enterContext (globals); | ||||||
|  | 
 | ||||||
|  | 	            result = scriptingEngine.invoke (thisObject, method, args); | ||||||
| 	            commitTransaction (); | 	            commitTransaction (); | ||||||
| 
 | 
 | ||||||
| 	        } catch (Exception wrong) { | 	        } catch (Exception wrong) { | ||||||
|  | @ -403,6 +406,9 @@ public class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 	    } | 	    } | ||||||
| 
 | 
 | ||||||
|  | 	    // exit execution context | ||||||
|  | 	    scriptingEngine.exitContext (); | ||||||
|  | 
 | ||||||
| 	    // make sure there is only one thread running per instance of this class | 	    // make sure there is only one thread running per instance of this class | ||||||
| 	    // if localrtx != rtx, the current thread has been aborted and there's no need to notify | 	    // if localrtx != rtx, the current thread has been aborted and there's no need to notify | ||||||
| 	    if (localrtx != rtx) { | 	    if (localrtx != rtx) { | ||||||
|  | @ -454,8 +460,13 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	    // wait for request, max 10 min | 	    // wait for request, max 10 min | ||||||
| 	    wait (1000*60*10); | 	    wait (1000*60*10); | ||||||
| 	    //  if no request arrived, release ressources and thread | 	    //  if no request arrived, release ressources and thread | ||||||
| 	    if (reqtype == NONE && rtx == localrtx) | 	    if (reqtype == NONE && rtx == localrtx) { | ||||||
|  | 	        // comment this in to release not just the thread, but also the scripting engine. | ||||||
|  | 	        // currently we don't do this because of the risk of memory leaks (objects from | ||||||
|  | 	        // framework referencing into the scripting engine) | ||||||
|  | 	        // scriptingEngine = null; | ||||||
| 	        rtx = null; | 	        rtx = null; | ||||||
|  | 	    } | ||||||
| 	} catch (InterruptedException ir) {} | 	} catch (InterruptedException ir) {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -469,13 +480,12 @@ public class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 	checkThread (); | 	checkThread (); | ||||||
| 	wait (app.requestTimeout); | 	wait (app.requestTimeout); | ||||||
|  	if (reqtype != NONE) { | 	if (reqtype != NONE) { | ||||||
| 	    app.logEvent ("Stopping Thread for Request "+app.getName()+"/"+req.path); | 	    app.logEvent ("Stopping Thread for Request "+app.getName()+"/"+req.path); | ||||||
| 	    stopThread (); | 	    stopThread (); | ||||||
| 	    res.reset (); | 	    res.reset (); | ||||||
| 	    res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>Request timed out.</pre>"); | 	    res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>Request timed out.</pre>"); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return res; | 	return res; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -505,17 +515,19 @@ public class RequestEvaluator implements Runnable { | ||||||
| 
 | 
 | ||||||
| 	checkThread (); | 	checkThread (); | ||||||
| 	wait (app.requestTimeout); | 	wait (app.requestTimeout); | ||||||
|  	if (reqtype != NONE) { | 	if (reqtype != NONE) { | ||||||
| 	    stopThread (); | 	    stopThread (); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// reset res for garbage collection (res.data may hold reference to evaluator) | ||||||
|  | 	res = null; | ||||||
| 	if (exception != null) | 	if (exception != null) | ||||||
| 	    throw (exception); | 	    throw (exception); | ||||||
| 	return result; | 	return result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected Object invokeDirectFunction (Object obj, String functionName, Object[] args) throws Exception { |     protected Object invokeDirectFunction (Object obj, String functionName, Object[] args) throws Exception { | ||||||
| 	return app.scriptingEngine.invoke (obj, functionName, args, null, this); | 	return scriptingEngine.invoke (obj, functionName, args); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public synchronized Object invokeFunction (Object object, String functionName, Object[] args) |     public synchronized Object invokeFunction (Object object, String functionName, Object[] args) | ||||||
|  | @ -532,10 +544,12 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	checkThread (); | 	checkThread (); | ||||||
| 	wait (60000l*15); // give internal call more time (15 minutes) to complete | 	wait (60000l*15); // give internal call more time (15 minutes) to complete | ||||||
| 
 | 
 | ||||||
|  	if (reqtype != NONE) { | 	if (reqtype != NONE) { | ||||||
| 	    stopThread (); | 	    stopThread (); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// reset res for garbage collection (res.data may hold reference to evaluator) | ||||||
|  | 	res = null; | ||||||
| 	if (exception != null) | 	if (exception != null) | ||||||
| 	    throw (exception); | 	    throw (exception); | ||||||
| 	return result; | 	return result; | ||||||
|  | @ -555,10 +569,12 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	checkThread (); | 	checkThread (); | ||||||
| 	wait (app.requestTimeout); | 	wait (app.requestTimeout); | ||||||
| 
 | 
 | ||||||
|  	if (reqtype != NONE) { | 	if (reqtype != NONE) { | ||||||
| 	    stopThread (); | 	    stopThread (); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// reset res for garbage collection (res.data may hold reference to evaluator) | ||||||
|  | 	res = null; | ||||||
| 	if (exception != null) | 	if (exception != null) | ||||||
| 	    throw (exception); | 	    throw (exception); | ||||||
| 	return result; | 	return result; | ||||||
|  | @ -603,7 +619,18 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |     /** | ||||||
|  |      *  Null out some fields, mostly for the sake of garbage collection. | ||||||
|  |      */ | ||||||
|  |     public void recycle () { | ||||||
|  |         res = null; | ||||||
|  |         req = null; | ||||||
|  |         session = null; | ||||||
|  |         args = null; | ||||||
|  |         requestPath = null; | ||||||
|  |         result = null; | ||||||
|  |         exception = null; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Check if an action with a given name is defined for a scripted object. If it is, |      * Check if an action with a given name is defined for a scripted object. If it is, | ||||||
|  | @ -613,12 +640,8 @@ public class RequestEvaluator implements Runnable { | ||||||
| 	if (obj == null) | 	if (obj == null) | ||||||
| 	    return null; | 	    return null; | ||||||
| 	String act = action == null ? "main_action" : action+"_action"; | 	String act = action == null ? "main_action" : action+"_action"; | ||||||
| 	try { | 	if (scriptingEngine.hasFunction (obj, act)) | ||||||
| 	    if (app.scriptingEngine.hasFunction (obj, act, this)) | 	    return act; | ||||||
| 	        return act; |  | ||||||
| 	} catch (ScriptingException x) { |  | ||||||
| 	    return null; |  | ||||||
| 	} |  | ||||||
| 	return null; | 	return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,19 +18,24 @@ import java.util.*; | ||||||
|  * from the RequestEvaluator object to resolve Macro handlers by type name. |  * from the RequestEvaluator object to resolve Macro handlers by type name. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| public class Skin { | public final class Skin { | ||||||
|  | 
 | ||||||
|  |     private Macro[] parts; | ||||||
|  |     private Application app; | ||||||
|  |     private char[] source; | ||||||
|  |     private int sourceLength; | ||||||
|  |     private HashSet sandbox; | ||||||
| 
 | 
 | ||||||
|     Macro[] parts; |  | ||||||
|     Application app; |  | ||||||
|     char[] source; |  | ||||||
|     int sourceLength; |  | ||||||
|     HashSet sandbox; |  | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Create a skin without any restrictions on which macros are allowed to be called from it |      * Create a skin without any restrictions on which macros are allowed to be called from it | ||||||
|      */ |      */ | ||||||
|     public Skin (String content, Application app) { |     public Skin (String content, Application app) { | ||||||
| 	this (content, app, null); | 	this.app = app; | ||||||
|  | 	sandbox = null; | ||||||
|  | 	source = content.toCharArray (); | ||||||
|  | 	sourceLength = source.length; | ||||||
|  | 	parse (); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -50,8 +55,8 @@ public class Skin { | ||||||
|     public Skin (char[] content, int length, Application app) { |     public Skin (char[] content, int length, Application app) { | ||||||
| 	this.app = app; | 	this.app = app; | ||||||
| 	this.sandbox = null; | 	this.sandbox = null; | ||||||
| 	this.source = content; | 	source = content; | ||||||
| 	this.sourceLength = length; | 	sourceLength = length; | ||||||
| 	parse (); | 	parse (); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -315,12 +320,12 @@ public class Skin { | ||||||
| 	            Object v = null; | 	            Object v = null; | ||||||
| 	            // remember length of response buffer before calling macro | 	            // remember length of response buffer before calling macro | ||||||
| 	            int oldLength = reval.res.getBufferLength (); | 	            int oldLength = reval.res.getBufferLength (); | ||||||
| 	            if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) { | 	            if (reval.scriptingEngine.hasFunction (handlerObject, name+"_macro")) { | ||||||
| 	                // System.err.println ("Getting macro from function"); | 	                // System.err.println ("Getting macro from function"); | ||||||
| 	                v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval); | 	                v = reval.scriptingEngine.invoke (handlerObject, name+"_macro", arguments); | ||||||
| 	            } else { | 	            } else { | ||||||
| 	                // System.err.println ("Getting macro from property"); | 	                // System.err.println ("Getting macro from property"); | ||||||
| 	                v = app.scriptingEngine.get (handlerObject, name, reval); | 	                v = reval.scriptingEngine.get (handlerObject, name); | ||||||
| 	            } | 	            } | ||||||
| 	            // check if macro wrote out to response buffer | 	            // check if macro wrote out to response buffer | ||||||
| 	            int newLength = reval.res.getBufferLength (); | 	            int newLength = reval.res.getBufferLength (); | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ import java.io.*; | ||||||
|  * applications and updates the evaluators if anything has changed. |  * applications and updates the evaluators if anything has changed. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| public class TypeManager { | public final class TypeManager { | ||||||
| 
 | 
 | ||||||
|     Application app; |     Application app; | ||||||
|     File appDir; |     File appDir; | ||||||
|  | @ -26,36 +26,23 @@ public class TypeManager { | ||||||
|     long idleSeconds = 120; // if idle for longer than 5 minutes, slow down |     long idleSeconds = 120; // if idle for longer than 5 minutes, slow down | ||||||
|     boolean rewire; |     boolean rewire; | ||||||
| 
 | 
 | ||||||
|     // this contains only those evaluatores which have already been initialized |     static String[] standardTypes = {"user", "global", "root", "hopobject"}; | ||||||
|     // and thus need to get updates |  | ||||||
|     List registeredEvaluators; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     static HashSet standardTypes; |  | ||||||
|     static { |  | ||||||
| 	standardTypes = new HashSet (); |  | ||||||
| 	standardTypes.add ("user"); |  | ||||||
| 	standardTypes.add ("global"); |  | ||||||
| 	standardTypes.add ("root"); |  | ||||||
| 	standardTypes.add ("hopobject"); |  | ||||||
|     } |  | ||||||
|   |   | ||||||
|     public TypeManager (Application app) { |     public TypeManager (Application app) { | ||||||
| 	this.app = app; |         this.app = app; | ||||||
| 	appDir = app.appDir; |         appDir = app.appDir; | ||||||
| 	// make sure the directories for the standard prototypes exist, and lament otherwise |         // make sure the directories for the standard prototypes exist, and lament otherwise | ||||||
| 	if (appDir.list().length == 0) { |         if (appDir.list().length == 0) { | ||||||
| 	    for (Iterator it=standardTypes.iterator (); it.hasNext (); ) { |             for (int i=0; i<standardTypes.length; i++) { | ||||||
| 	        File f = new File (appDir, (String) it.next ()); |                 File f = new File (appDir, standardTypes[i]); | ||||||
| 	        if (!f.exists() && !f.mkdir ())	 |                 if (!f.exists() && !f.mkdir ())	 | ||||||
| 	            app.logEvent ("Warning: directory "+f.getAbsolutePath ()+" could not be created."); |                     app.logEvent ("Warning: directory "+f.getAbsolutePath ()+" could not be created."); | ||||||
| 	        else if (!f.isDirectory ()) |                 else if (!f.isDirectory ()) | ||||||
| 	            app.logEvent ("Warning: "+f.getAbsolutePath ()+" is not a directory."); |                     app.logEvent ("Warning: "+f.getAbsolutePath ()+" is not a directory."); | ||||||
| 	    } |             } | ||||||
| 	} |         } | ||||||
| 	prototypes = new HashMap (); |         prototypes = new HashMap (); | ||||||
| 	zipfiles = new HashMap (); |         zipfiles = new HashMap (); | ||||||
| 	registeredEvaluators = Collections.synchronizedList (new ArrayList ()); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -64,7 +51,17 @@ public class TypeManager { | ||||||
|      * compile or evaluate any scripts. |      * compile or evaluate any scripts. | ||||||
|      */ |      */ | ||||||
|     public void createPrototypes () { |     public void createPrototypes () { | ||||||
| 	check (false); |         checkFiles (); | ||||||
|  |         // check if standard prototypes have been created | ||||||
|  |         // if not, create them. | ||||||
|  |         for (int i=0; i<standardTypes.length; i++) { | ||||||
|  |             String pname = standardTypes[i]; | ||||||
|  |             if (prototypes.get (pname) == null) { | ||||||
|  |                 Prototype proto = new Prototype (pname, app); | ||||||
|  |                 registerPrototype (pname, new File (appDir, pname), proto); | ||||||
|  |                 prototypes.put (pname, proto); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -73,10 +70,10 @@ public class TypeManager { | ||||||
|      * If so, update prototypes and scripts. |      * If so, update prototypes and scripts. | ||||||
|      */ |      */ | ||||||
|     public synchronized void checkPrototypes () { |     public synchronized void checkPrototypes () { | ||||||
| 	if (System.currentTimeMillis () - lastCheck  < 500l) | 	if (System.currentTimeMillis () - lastCheck  < 1000l) | ||||||
| 	    return; | 	    return; | ||||||
| 	try { | 	try { | ||||||
| 	    check (true); | 	    checkFiles (); | ||||||
| 	} catch (Exception ignore) {} | 	} catch (Exception ignore) {} | ||||||
| 	lastCheck = System.currentTimeMillis (); | 	lastCheck = System.currentTimeMillis (); | ||||||
|     } |     } | ||||||
|  | @ -84,7 +81,7 @@ public class TypeManager { | ||||||
|     /** |     /** | ||||||
|      * Run through application's prototype directories and check if anything has been updated. |      * Run through application's prototype directories and check if anything has been updated. | ||||||
|      */ |      */ | ||||||
|     public void check (boolean update) { |     public void checkFiles () { | ||||||
| 	// long now = System.currentTimeMillis (); | 	// long now = System.currentTimeMillis (); | ||||||
| 	// System.out.print ("checking "+Thread.currentThread ()); | 	// System.out.print ("checking "+Thread.currentThread ()); | ||||||
| 	File[] list = appDir.listFiles (); | 	File[] list = appDir.listFiles (); | ||||||
|  | @ -96,12 +93,12 @@ public class TypeManager { | ||||||
| 	    if (proto != null) { | 	    if (proto != null) { | ||||||
| 	        // check if existing prototype needs update | 	        // check if existing prototype needs update | ||||||
| 	        // app.logEvent (protoDir.lastModified ()); | 	        // app.logEvent (protoDir.lastModified ()); | ||||||
| 	        updatePrototype (filename, list[i], proto); | 	        // updatePrototype (filename, list[i], proto); | ||||||
| 	    } else if (list[i].isDirectory () && isValidTypeName (filename)) { | 	    } else if (list[i].isDirectory () && isValidTypeName (filename)) { | ||||||
| 	        // leave out ".." and other directories that contain "." | 	        // leave out ".." and other directories that contain "." | ||||||
| 	        // create new prototype | 	        // create new prototype | ||||||
| 	        proto = new Prototype (filename, app); | 	        proto = new Prototype (filename, app); | ||||||
| 	        registerPrototype (filename, list[i], proto, update); | 	        registerPrototype (filename, list[i], proto); | ||||||
| 	        prototypes.put (filename, proto); | 	        prototypes.put (filename, proto); | ||||||
| 	        // give logger thread a chance to tell what's going on | 	        // give logger thread a chance to tell what's going on | ||||||
| 	        // Thread.yield(); | 	        // Thread.yield(); | ||||||
|  | @ -122,19 +119,6 @@ public class TypeManager { | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
| 		 | 		 | ||||||
| 	// check if standard prototypes have been created |  | ||||||
| 	// as a performance hack, we only do this when update is false, i.e. the first time we're called. |  | ||||||
| 	if (!update) { |  | ||||||
| 	    for (Iterator it=standardTypes.iterator (); it.hasNext (); ) { |  | ||||||
| 	        String pname = (String) it.next(); |  | ||||||
| 	        if (prototypes.get (pname) == null) { |  | ||||||
| 	            Prototype proto = new Prototype (pname, app); |  | ||||||
| 	            registerPrototype (pname, new File (appDir, pname), proto, false); |  | ||||||
| 	            prototypes.put (pname, proto); |  | ||||||
| 	        } |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	if (rewire) { | 	if (rewire) { | ||||||
| 	    // there have been changes in the  DbMappings | 	    // there have been changes in the  DbMappings | ||||||
| 	    app.rewireDbMappings (); | 	    app.rewireDbMappings (); | ||||||
|  | @ -182,7 +166,8 @@ public class TypeManager { | ||||||
|     /** |     /** | ||||||
|      *  Create a prototype from a directory containing scripts and other stuff |      *  Create a prototype from a directory containing scripts and other stuff | ||||||
|      */ |      */ | ||||||
|     public void registerPrototype (String name, File dir, Prototype proto, boolean update) { |     public void registerPrototype (String name, File dir, Prototype proto) { | ||||||
|  |         // System.err.println ("REGISTER PROTO: "+app.getName()+"/"+name); | ||||||
|         // app.logEvent ("registering prototype "+name); |         // app.logEvent ("registering prototype "+name); | ||||||
| 
 | 
 | ||||||
|         // show the type checker thread that there has been type activity |         // show the type checker thread that there has been type activity | ||||||
|  | @ -194,84 +179,38 @@ public class TypeManager { | ||||||
|         HashMap nskins = new HashMap (); |         HashMap nskins = new HashMap (); | ||||||
|         HashMap updatables = new HashMap (); |         HashMap updatables = new HashMap (); | ||||||
| 
 | 
 | ||||||
|         if (update) { |  | ||||||
|             String list[] = dir.list(); |  | ||||||
|             for (int i=0; i<list.length; i++) { |  | ||||||
|                 File tmpfile = new File (dir, list[i]); |  | ||||||
|                 int dot = list[i].indexOf ("."); |  | ||||||
| 
 |  | ||||||
|                 if (dot < 0) |  | ||||||
|                     continue; |  | ||||||
| 
 |  | ||||||
|                 String tmpname = list[i].substring(0, dot); |  | ||||||
| 
 |  | ||||||
|                 if (list[i].endsWith (app.templateExtension)) { |  | ||||||
|                     try { |  | ||||||
|                         Template t = new Template (tmpfile, tmpname, proto); |  | ||||||
|                         updatables.put (list[i], t); |  | ||||||
|                         ntemp.put (tmpname, t); |  | ||||||
|                     } catch (Throwable x) { |  | ||||||
|                         app.logEvent ("Error creating prototype: "+x); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                 } else if (list[i].endsWith (app.scriptExtension) && tmpfile.length () > 0) { |  | ||||||
|                     try { |  | ||||||
|                         FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto); |  | ||||||
|                         updatables.put (list[i], ff); |  | ||||||
|                         nfunc.put (tmpname, ff); |  | ||||||
|                     } catch (Throwable x) { |  | ||||||
|                         app.logEvent ("Error creating prototype: "+x); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                 } else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) { |  | ||||||
|                     try { |  | ||||||
|                         ActionFile af = new ActionFile (tmpfile, tmpname, proto); |  | ||||||
|                         updatables.put (list[i], af); |  | ||||||
|                         nact.put (tmpname, af); |  | ||||||
|                     } catch (Throwable x) { |  | ||||||
|                         app.logEvent ("Error creating prototype: "+x); |  | ||||||
|                     } |  | ||||||
|                 }  else if (list[i].endsWith (app.skinExtension)) { |  | ||||||
|                     try { |  | ||||||
|                         SkinFile sf = new SkinFile (tmpfile, tmpname, proto); |  | ||||||
|                         updatables.put (list[i], sf); |  | ||||||
|                         nskins.put (tmpname, sf); |  | ||||||
|                     } catch (Throwable x) { |  | ||||||
|                         app.logEvent ("Error creating prototype: "+x); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Create and register type properties file |         // Create and register type properties file | ||||||
|         File propfile = new File (dir, "type.properties"); |         File propfile = new File (dir, "type.properties"); | ||||||
|         SystemProperties props = new SystemProperties (propfile.getAbsolutePath ()); |         SystemProperties props = new SystemProperties (propfile.getAbsolutePath ()); | ||||||
|         DbMapping dbmap = new DbMapping (app, name, props); |         DbMapping dbmap = new DbMapping (app, name, props); | ||||||
|         updatables.put ("type.properties", dbmap); |         updatables.put ("type.properties", dbmap); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         proto.templates = ntemp; |         proto.templates = ntemp; | ||||||
|         proto.functions = nfunc; |         proto.functions = nfunc; | ||||||
|         proto.actions = nact; |         proto.actions = nact; | ||||||
|         proto.skins = nskins; |         proto.skins = nskins; | ||||||
|         proto.updatables = updatables; |         proto.updatables = updatables; | ||||||
| 
 | 
 | ||||||
|         // init prototype on evaluators that are already initialized. |         // app.scriptingEngine.updatePrototype (proto); | ||||||
|         /* Iterator evals = getRegisteredRequestEvaluators (); |  | ||||||
|         while (evals.hasNext ()) { |  | ||||||
|             RequestEvaluator reval = (RequestEvaluator) evals.next (); |  | ||||||
|             proto.initRequestEvaluator (reval); |  | ||||||
|         }*/ |  | ||||||
|         app.scriptingEngine.updatePrototype (proto); |  | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|     * Update a prototype based on the directory which defines it. |     * Update a prototype based on the directory which defines it. | ||||||
|     */ |     */ | ||||||
|     public void updatePrototype (String name, File dir, Prototype proto) { |     public void updatePrototype (String name) { | ||||||
|  |         // System.err.println ("UPDATE PROTO: "+app.getName()+"/"+name); | ||||||
|  |         Prototype proto = getPrototype (name); | ||||||
|  |         if (proto == null) | ||||||
|  |             return; | ||||||
|  |         if (System.currentTimeMillis() - proto.getLastCheck() < 1000) | ||||||
|  |             return; | ||||||
| 
 | 
 | ||||||
|  |         synchronized (proto) { | ||||||
|  |         if (System.currentTimeMillis() - proto.getLastCheck() < 1000) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         File dir = new File (appDir, name); | ||||||
|         boolean needsUpdate = false; |         boolean needsUpdate = false; | ||||||
|         HashSet updatables = null; |         HashSet updatables = null; | ||||||
| 
 | 
 | ||||||
|  | @ -290,22 +229,22 @@ public class TypeManager { | ||||||
|         if (proto.lastUpdate < dir.lastModified ()) { |         if (proto.lastUpdate < 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 (app.templateExtension) || fn.endsWith (app.scriptExtension) || |                     if (fn.endsWith (app.templateExtension) || fn.endsWith (app.scriptExtension) || | ||||||
| 	    	fn.endsWith (app.actionExtension) || fn.endsWith (app.skinExtension) || | 	    	fn.endsWith (app.actionExtension) || fn.endsWith (app.skinExtension) || | ||||||
| 	    	"type.properties".equalsIgnoreCase (fn)) { | 	    	"type.properties".equalsIgnoreCase (fn)) { | ||||||
| 	            needsUpdate = true; |                         needsUpdate = true; | ||||||
| 	            // updatables.add ("[new:"+proto.getName()+"/"+fn+"]"); |                         // updatables.add ("[new:"+proto.getName()+"/"+fn+"]"); | ||||||
|                       } |                     } | ||||||
| 	    } |                 } | ||||||
|              } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (!needsUpdate) |         if (!needsUpdate) { | ||||||
| 	return; |             proto.markChecked (); | ||||||
| 
 |             return; | ||||||
|         proto.lastUpdate = System.currentTimeMillis (); |         } | ||||||
| 
 | 
 | ||||||
|         // let the thread know we had to do something. |         // let the thread know we had to do something. | ||||||
|         idleSeconds = 0; |         idleSeconds = 0; | ||||||
|  | @ -381,31 +320,12 @@ public class TypeManager { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         app.scriptingEngine.updatePrototype (proto); |         proto.markUpdated(); | ||||||
|  | 
 | ||||||
|  |         } // end of synchronized (proto) | ||||||
|  | 
 | ||||||
|  |         // app.scriptingEngine.updatePrototype (proto); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     /*public void initRequestEvaluator (RequestEvaluator reval) { |  | ||||||
|         if (!registeredEvaluators.contains (reval)) |  | ||||||
|             registeredEvaluators.add (reval); |  | ||||||
|         for (Iterator it = prototypes.values().iterator(); it.hasNext(); ) { |  | ||||||
|             Prototype p = (Prototype) it.next (); |  | ||||||
|             p.initRequestEvaluator (reval); |  | ||||||
|         } |  | ||||||
|         reval.initialized = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void unregisterRequestEvaluator (RequestEvaluator reval) { |  | ||||||
|         registeredEvaluators.remove (reval); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public Iterator getRegisteredRequestEvaluators () { |  | ||||||
|         return registeredEvaluators.iterator (); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public int countRegisteredRequestEvaluators () { |  | ||||||
|         return registeredEvaluators.size (); |  | ||||||
|     } */ |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -74,6 +74,8 @@ public class ZippedAppFile implements Updatable { | ||||||
| 	                    // System.err.println ("["+content+"]"); | 	                    // System.err.println ("["+content+"]"); | ||||||
| 	                    ActionFile act = new ActionFile (content, name, proto); | 	                    ActionFile act = new ActionFile (content, name, proto); | ||||||
| 	                    proto.actions.put (name, act); | 	                    proto.actions.put (name, act); | ||||||
|  | 	                    // mark prototype as updated | ||||||
|  | 	                    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 (".")); | ||||||
|  | @ -81,6 +83,8 @@ public class ZippedAppFile implements Updatable { | ||||||
| 	                    // System.err.println ("["+content+"]"); | 	                    // System.err.println ("["+content+"]"); | ||||||
| 	                    Template tmp = new Template (content, name, proto); | 	                    Template tmp = new Template (content, name, proto); | ||||||
| 	                    proto.templates.put (name, tmp); | 	                    proto.templates.put (name, tmp); | ||||||
|  | 	                    // mark prototype as updated | ||||||
|  | 	                    proto.markUpdated (); | ||||||
| 	                } | 	                } | ||||||
| 	                else if (fname.endsWith (".skin")) { | 	                else if (fname.endsWith (".skin")) { | ||||||
| 	                    String name = fname.substring (0, fname.lastIndexOf (".")); | 	                    String name = fname.substring (0, fname.lastIndexOf (".")); | ||||||
|  | @ -95,12 +99,16 @@ public class ZippedAppFile implements Updatable { | ||||||
| 	                    // System.err.println ("["+content+"]"); | 	                    // System.err.println ("["+content+"]"); | ||||||
| 	                    FunctionFile ff = new FunctionFile (content, name, proto); | 	                    FunctionFile ff = new FunctionFile (content, name, proto); | ||||||
| 	                    proto.functions.put (name, ff); | 	                    proto.functions.put (name, ff); | ||||||
|  | 	                    // mark prototype as updated | ||||||
|  | 	                    proto.markUpdated (); | ||||||
| 	                } | 	                } | ||||||
| 	                else if ("type.properties".equalsIgnoreCase (fname)) { | 	                else if ("type.properties".equalsIgnoreCase (fname)) { | ||||||
| 	                    String name = fname.substring (0, fname.lastIndexOf (".")); | 	                    String name = fname.substring (0, fname.lastIndexOf (".")); | ||||||
| 	                    SystemProperties props = new SystemProperties (zip.getInputStream (entry)); | 	                    SystemProperties props = new SystemProperties (zip.getInputStream (entry)); | ||||||
| 	                    // DbMapping does its own registering, just construct it. | 	                    // DbMapping does its own registering, just construct it. | ||||||
| 	                    new DbMapping (app, proto.getName (), props); | 	                    new DbMapping (app, proto.getName (), props); | ||||||
|  | 	                    // mark prototype as updated | ||||||
|  | 	                    proto.markUpdated (); | ||||||
| 	                } | 	                } | ||||||
| 	            } | 	            } | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| // ScriptingEnvironment.java | // ScriptingEngine.java | ||||||
| // Copyright (c) Hannes Wallnöfer 1998-2001 | // Copyright (c) Hannes Wallnöfer 1998-2001 | ||||||
| 
 | 
 | ||||||
| package helma.scripting; | package helma.scripting; | ||||||
|  | @ -13,35 +13,37 @@ 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 | ||||||
|  * usable by the Helma application server. |  * usable by the Helma application server. | ||||||
|  */ |  */ | ||||||
| public interface ScriptingEnvironment { | public interface ScriptingEngine { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Initialize the environment using the given properties |      *  This method is called when an execution context for a request | ||||||
|  |      *  evaluation is entered. The globals parameter contains the global values | ||||||
|  |      *  to be applied during this executino context. | ||||||
|      */ |      */ | ||||||
|     public void init (Application app, Properties props) throws ScriptingException; |     public void enterContext (HashMap globals) throws ScriptingException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * A prototype has been updated and must be re-evaluated. |      *   This method is called to let the scripting engine know that the current | ||||||
|  |      *   execution context has terminated. | ||||||
|      */ |      */ | ||||||
|     public void updatePrototype (Prototype prototype); |     public void exitContext (); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 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, String functionName, Object[] args, |     public Object invoke (Object thisObject, String functionName, Object[] args) | ||||||
| 		HashMap globals, RequestEvaluator reval) |  | ||||||
| 		throws ScriptingException; | 		throws ScriptingException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      *  Get a property on an object |      *  Get a property on an object | ||||||
|      */ |      */ | ||||||
|     public Object get (Object thisObject, String key, RequestEvaluator reval); |     public Object get (Object thisObject, String key); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      *  Return true if a function by that name is defined for that object. |      *  Return true if a function by that name is defined for that object. | ||||||
|      */ |      */ | ||||||
|     public boolean hasFunction (Object thisObject, String functionName, RequestEvaluator reval) |     public boolean hasFunction (Object thisObject, String functionName); | ||||||
| 		throws ScriptingException; |  | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										18
									
								
								src/helma/scripting/fesi/FesiEngineFactory.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/helma/scripting/fesi/FesiEngineFactory.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | // FesiEngineFactory.java | ||||||
|  | // Copyright (c) Hannes Wallnöfer 2002 | ||||||
|  | 
 | ||||||
|  | package helma.scripting.fesi; | ||||||
|  | 
 | ||||||
|  | import helma.scripting.*; | ||||||
|  | import helma.framework.core.*; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  *  Factory class for FESI evalator engines. | ||||||
|  |  */ | ||||||
|  | public final class FesiEngineFactory  { | ||||||
|  | 
 | ||||||
|  |     public static ScriptingEngine getEngine (Application app, RequestEvaluator reval) { | ||||||
|  | 	return new FesiEvaluator (app, reval); | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  | } | ||||||
|  | @ -22,16 +22,16 @@ import Acme.LruHashtable; | ||||||
|  * This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter. |  * This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| public final class FesiEvaluator { | public final class FesiEvaluator implements ScriptingEngine { | ||||||
| 
 | 
 | ||||||
|     // the application we're running in |     // the application we're running in | ||||||
|     public Application app; |     public final Application app; | ||||||
| 
 | 
 | ||||||
|     // The FESI evaluator |     // The FESI evaluator | ||||||
|     Evaluator evaluator; |     final Evaluator evaluator; | ||||||
|     |     | ||||||
|     // the global object |     // the global object | ||||||
|     GlobalObject global; |     final GlobalObject global; | ||||||
| 
 | 
 | ||||||
|     // caching table for JavaScript object wrappers |     // caching table for JavaScript object wrappers | ||||||
|     LruHashtable wrappercache; |     LruHashtable wrappercache; | ||||||
|  | @ -40,7 +40,7 @@ public final class FesiEvaluator { | ||||||
|     Hashtable prototypes; |     Hashtable prototypes; | ||||||
| 
 | 
 | ||||||
|     // the request evaluator instance owning this fesi evaluator |     // the request evaluator instance owning this fesi evaluator | ||||||
|     RequestEvaluator reval; |     final RequestEvaluator reval; | ||||||
|      |      | ||||||
|     // extensions loaded by this evaluator |     // extensions loaded by this evaluator | ||||||
|     static String[] extensions = new String[] { |     static String[] extensions = new String[] { | ||||||
|  | @ -57,6 +57,7 @@ public final class FesiEvaluator { | ||||||
|     // do lazy cleanup |     // do lazy cleanup | ||||||
|     Map lastGlobals = null; |     Map lastGlobals = null; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     public FesiEvaluator (Application app, RequestEvaluator reval) { |     public FesiEvaluator (Application app, RequestEvaluator reval) { | ||||||
| 	this.app = app; | 	this.app = app; | ||||||
| 	this.reval = reval; | 	this.reval = reval; | ||||||
|  | @ -67,7 +68,7 @@ public final class FesiEvaluator { | ||||||
| 	    evaluator.reval = this; | 	    evaluator.reval = this; | ||||||
| 	    global = evaluator.getGlobalObject(); | 	    global = evaluator.getGlobalObject(); | ||||||
| 	    for (int i=0; i<extensions.length; i++) | 	    for (int i=0; i<extensions.length; i++) | ||||||
| 	        evaluator.addExtension (extensions[i]); |              evaluator.addExtension (extensions[i]); | ||||||
| 	    HopExtension hopx = new HopExtension (app); | 	    HopExtension hopx = new HopExtension (app); | ||||||
| 	    hopx.initializeExtension (this); | 	    hopx.initializeExtension (this); | ||||||
| 	    MailExtension mailx = (MailExtension) evaluator.addExtension ("helma.scripting.fesi.extensions.MailExtension"); | 	    MailExtension mailx = (MailExtension) evaluator.addExtension ("helma.scripting.fesi.extensions.MailExtension"); | ||||||
|  | @ -93,12 +94,66 @@ public final class FesiEvaluator { | ||||||
| 	Collection prototypes = app.getPrototypes(); | 	Collection prototypes = app.getPrototypes(); | ||||||
| 	for (Iterator i=prototypes.iterator(); i.hasNext(); ) { | 	for (Iterator i=prototypes.iterator(); i.hasNext(); ) { | ||||||
| 	    Prototype proto = (Prototype) i.next (); | 	    Prototype proto = (Prototype) i.next (); | ||||||
| 	    evaluatePrototype (proto); | 	    initPrototype (proto); | ||||||
| 	} | 	} | ||||||
|  | 	// always fully initialize global prototype, because | ||||||
|  | 	// we always need it and there's no chance to trigger | ||||||
|  | 	// creation on demand. | ||||||
|  | 	getPrototype ("global"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void initPrototype (Prototype prototype) { | ||||||
|  |         // System.err.println ("FESI INIT PROTO "+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 = getRawPrototype (parent.getName ()); | ||||||
|  | 	    if (opp == null) { | ||||||
|  | 	        initPrototype (parent); | ||||||
|  | 	        opp = getRawPrototype (parent.getName ()); | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  | 	String name = prototype.getName (); | ||||||
|  | 	if (!"global".equalsIgnoreCase (name) && !"hopobject".equalsIgnoreCase (name) && opp == null) { | ||||||
|  | 	    if (app.isJavaPrototype (name)) | ||||||
|  | 	        opp = getRawPrototype ("__javaobject__"); | ||||||
|  | 	    else | ||||||
|  | 	        opp = getRawPrototype ("hopobject"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// if prototype doesn't exist (i.e. is a standard prototype built by HopExtension), create it. | ||||||
|  | 	op = getRawPrototype (name); | ||||||
|  | 	if (op == null) { | ||||||
|  | 	    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); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Register a constructor for all types except global. | ||||||
|  | 	// This will first create a new prototyped hopobject and then calls | ||||||
|  |                   // the actual (scripted) constructor on it. | ||||||
|  | 	if (!"global".equalsIgnoreCase (name)) { | ||||||
|  |              if (!"root".equalsIgnoreCase (name) && !"user".equalsIgnoreCase (name)) | ||||||
|  |              try { | ||||||
|  | 	        FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); | ||||||
|  | 	        global.putHiddenProperty (name, new NodeConstructor (name, fp, this)); | ||||||
|  | 	    } catch (EcmaScriptException ignore) {} | ||||||
|  | 	} | ||||||
|  | 	// app.typemgr.updatePrototype (prototype.getName()); | ||||||
|  | 	// evaluatePrototype (prototype); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void evaluatePrototype (Prototype prototype) { |     void evaluatePrototype (Prototype prototype) { | ||||||
| 
 |         // System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this); | ||||||
| 	ObjectPrototype op = null; | 	ObjectPrototype op = null; | ||||||
| 
 | 
 | ||||||
| 	// get the prototype's prototype if possible and necessary | 	// get the prototype's prototype if possible and necessary | ||||||
|  | @ -119,7 +174,6 @@ public final class FesiEvaluator { | ||||||
| 	    else | 	    else | ||||||
| 	        opp = getPrototype ("hopobject"); | 	        opp = getPrototype ("hopobject"); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	// if prototype doesn't exist (i.e. is a standard prototype built by HopExtension), create it. | 	// if prototype doesn't exist (i.e. is a standard prototype built by HopExtension), create it. | ||||||
| 	op = getPrototype (name); | 	op = getPrototype (name); | ||||||
| 	if (op == null) { | 	if (op == null) { | ||||||
|  | @ -129,18 +183,19 @@ public final class FesiEvaluator { | ||||||
| 	    } catch (EcmaScriptException ignore) {} | 	    } catch (EcmaScriptException ignore) {} | ||||||
| 	    putPrototype (name, op); | 	    putPrototype (name, op); | ||||||
| 	} else { | 	} else { | ||||||
|  |                       // reset prototype to original state | ||||||
|  | 	    resetPrototype (op); | ||||||
| 	    // set parent prototype just in case it has been changed | 	    // set parent prototype just in case it has been changed | ||||||
| 	    op.setPrototype (opp); | 	    op.setPrototype (opp); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	resetPrototype (op); |  | ||||||
| 
 |  | ||||||
| 	// Register a constructor for all types except global. | 	// Register a constructor for all types except global. | ||||||
| 	// This will first create a node and then call the actual (scripted) constructor on it. | 	// This will first create a new prototyped hopobject and then calls  | ||||||
| 	if (!"global".equalsIgnoreCase (name)) { |                   // the actual (scripted) constructor on it. | ||||||
|  | 	if (!"global".equalsIgnoreCase (name) && !"root".equalsIgnoreCase (name) && !"user".equalsIgnoreCase (name)) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); | 	        FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); | ||||||
| 	        evaluator.getGlobalObject().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.functions.values().iterator(); it.hasNext(); ) { | 	for (Iterator it = prototype.functions.values().iterator(); it.hasNext(); ) { | ||||||
|  | @ -175,7 +230,6 @@ public final class FesiEvaluator { | ||||||
| 	    String prop = en.nextElement ().toString (); | 	    String prop = en.nextElement ().toString (); | ||||||
| 	    try { | 	    try { | ||||||
| 	        ESValue esv = op.getProperty (prop, prop.hashCode ()); | 	        ESValue esv = op.getProperty (prop, prop.hashCode ()); | ||||||
| 	        // System.err.println (protoname+"."+obj+"   ->   "+esv.getClass()); |  | ||||||
| 	        if (esv instanceof ConstructedFunctionObject || esv instanceof FesiActionAdapter.ThrowException) | 	        if (esv instanceof ConstructedFunctionObject || esv instanceof FesiActionAdapter.ThrowException) | ||||||
| 	            op.deleteProperty (prop, prop.hashCode()); | 	            op.deleteProperty (prop, prop.hashCode()); | ||||||
| 	    } catch (Exception x) {} | 	    } catch (Exception x) {} | ||||||
|  | @ -183,51 +237,40 @@ public final class FesiEvaluator { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Invoke a function on some object, using the given arguments and global vars. |      *  This method is called when an execution context for a request | ||||||
|  |      *  evaluation is entered. The globals parameter contains the global values | ||||||
|  |      *  to be applied during this executino context. | ||||||
|      */ |      */ | ||||||
|     public Object invoke (Object thisObject, String functionName, Object[] args, HashMap globals) throws ScriptingException { |     public void enterContext (HashMap globals) throws ScriptingException { | ||||||
| 	ESObject eso = null; | 	// first loop through existing prototypes and update them if necessary | ||||||
| 	if (thisObject == null) | 	for (Enumeration e=prototypes.elements(); e.hasMoreElements(); ) { | ||||||
| 	    eso = global; | 	    TypeInfo info = (TypeInfo) e.nextElement (); | ||||||
| 	else | 	    // only update prototype if it has already been initialized.  | ||||||
| 	    eso = getElementWrapper (thisObject); | 	    // otherwise, this will be done on demand | ||||||
| 
 | 	    if (info.lastUpdate > 0) { | ||||||
| 	GlobalObject global = evaluator.getGlobalObject (); | 	        Prototype p = app.typemgr.getPrototype (info.protoName); | ||||||
| 
 | 	        if (p != null) { | ||||||
| 	// if we are provided with global variables to set for this invocation, | 	            app.typemgr.updatePrototype(info.protoName); | ||||||
| 	// remember the global variables before invocation to be able to reset them afterwards. | 	            if (p.getLastUpdate () > info.lastUpdate) { | ||||||
| 	Set globalVariables = null; | 	                evaluatePrototype(p); | ||||||
| 	try { | 	                info.lastUpdate = p.getLastUpdate (); | ||||||
| 	    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 && globals != lastGlobals) { |  | ||||||
| 	        // 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 | 	// set globals on the global object | ||||||
| 	        for (Iterator i=globals.keySet().iterator(); i.hasNext(); ) { | 	if (globals != null && globals != lastGlobals) { | ||||||
| 	            String k = (String) i.next(); | 	    // loop through global vars and set them | ||||||
| 	            Object v = globals.get (k); | 	    for (Iterator i=globals.keySet().iterator(); i.hasNext(); ) { | ||||||
| 	            ESValue sv = null; | 	        String k = (String) i.next(); | ||||||
|  | 	        Object v = globals.get (k); | ||||||
|  | 	        ESValue sv = null; | ||||||
|  | 	        try { | ||||||
| 	            // we do a lot of extra work to make access to global variables | 	            // 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 | 	            // 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 | 	            // that expose properties and functions in a special way instead of just going | ||||||
| 	            // with the standard java object wrappers. | 	            // with the standard java object wrappers. | ||||||
| 
 |  | ||||||
| 	            if (v instanceof Map) { | 	            if (v instanceof Map) { | ||||||
| 	                sv = new ESMapWrapper (this, (Map) v); | 	                sv = new ESMapWrapper (this, (Map) v); | ||||||
| 	            } else if ("path".equals (k)) { | 	            } else if ("path".equals (k)) { | ||||||
|  | @ -255,9 +298,53 @@ public final class FesiEvaluator { | ||||||
| 	                sv = ESLoader.normalizeValue (v, evaluator); | 	                sv = ESLoader.normalizeValue (v, evaluator); | ||||||
| 	            } | 	            } | ||||||
| 	            global.putHiddenProperty (k, sv); | 	            global.putHiddenProperty (k, sv); | ||||||
|  | 	        } catch (Exception x) { | ||||||
|  | 	            app.logEvent ("Error setting global variable "+k+": "+x); | ||||||
| 	        } | 	        } | ||||||
| 	        // remember the globals set on this evaluator | 	    } | ||||||
| 	        // lastGlobals = globals; | 	} | ||||||
|  | 	// remember the globals set on this evaluator | ||||||
|  | 	lastGlobals = globals; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      *   This method is called to let the scripting engine know that the current | ||||||
|  |      *   execution context has terminated. | ||||||
|  |      */ | ||||||
|  |     public void exitContext () { | ||||||
|  | 	// loop through previous globals and unset them, if necessary. | ||||||
|  | 	if (lastGlobals != null) { | ||||||
|  | 	    for (Iterator i=lastGlobals.keySet().iterator(); i.hasNext(); ) { | ||||||
|  | 	        String g = (String) i.next (); | ||||||
|  | 	        try { | ||||||
|  | 	            global.deleteProperty (g, g.hashCode()); | ||||||
|  | 	        } catch (Exception x) { | ||||||
|  | 	            System.err.println ("Error resetting global property: "+g); | ||||||
|  | 	        } | ||||||
|  | 	    } | ||||||
|  | 	    lastGlobals = null; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Invoke a function on some object, using the given arguments and global vars. | ||||||
|  |      */ | ||||||
|  |     public Object invoke (Object thisObject, String functionName, Object[] args) throws ScriptingException { | ||||||
|  | 	ESObject eso = null; | ||||||
|  | 	if (thisObject == null) | ||||||
|  | 	    eso = global; | ||||||
|  | 	else | ||||||
|  | 	    eso = getElementWrapper (thisObject); | ||||||
|  | 	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); | ||||||
| 	    } | 	    } | ||||||
| 	    evaluator.thread = Thread.currentThread (); | 	    evaluator.thread = Thread.currentThread (); | ||||||
| 	    ESValue retval =  eso.doIndirectCall (evaluator, eso, functionName, esv); | 	    ESValue retval =  eso.doIndirectCall (evaluator, eso, functionName, esv); | ||||||
|  | @ -276,24 +363,6 @@ public final class FesiEvaluator { | ||||||
| 	        x.printStackTrace (); | 	        x.printStackTrace (); | ||||||
| 	    } | 	    } | ||||||
| 	    throw new ScriptingException (msg); | 	    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 (); |  | ||||||
| 	            try { |  | ||||||
| 	                if (!globalVariables.contains (g) && |  | ||||||
| 				!(global.getProperty (g, g.hashCode()) instanceof BuiltinFunctionObject)) |  | ||||||
| 	                    global.deleteProperty (g, g.hashCode()); |  | ||||||
| 	            } catch (Exception x) { |  | ||||||
| 	                System.err.println ("Error resetting global property: "+g); |  | ||||||
| 	            } |  | ||||||
| 	        } |  | ||||||
| 	    } |  | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -303,13 +372,11 @@ public final class FesiEvaluator { | ||||||
|      * is a java object) with that name. |      * is a java object) with that name. | ||||||
|      */ |      */ | ||||||
|     public boolean hasFunction (Object obj, String fname) { |     public boolean hasFunction (Object obj, String fname) { | ||||||
| 	ESObject eso = null; | 	// System.err.println ("HAS_FUNC: "+fname); | ||||||
| 	if (obj == null) | 	String protoname = app.getPrototypeName (obj); | ||||||
| 	    eso = evaluator.getGlobalObject (); |  | ||||||
| 	else |  | ||||||
| 	    eso = getElementWrapper (obj); |  | ||||||
| 	try { | 	try { | ||||||
| 	    ESValue func = eso.getProperty (fname, fname.hashCode()); | 	    ObjectPrototype op = getPrototype (protoname); | ||||||
|  | 	    ESValue func = op.getProperty (fname, fname.hashCode()); | ||||||
| 	    if (func != null && func instanceof FunctionPrototype) | 	    if (func != null && func instanceof FunctionPrototype) | ||||||
| 	        return true; | 	        return true; | ||||||
| 	} catch (EcmaScriptException esx) { | 	} catch (EcmaScriptException esx) { | ||||||
|  | @ -324,7 +391,7 @@ public final class FesiEvaluator { | ||||||
|      * Check if an object has a defined property (public field if it |      * Check if an object has a defined property (public field if it | ||||||
|      * is a java object) with that name. |      * is a java object) with that name. | ||||||
|      */ |      */ | ||||||
|     public Object getProperty (Object obj, String propname) { |     public Object get (Object obj, String propname) { | ||||||
| 	if (obj == null || propname == null) | 	if (obj == null || propname == null) | ||||||
| 	    return null; | 	    return null; | ||||||
| 
 | 
 | ||||||
|  | @ -333,7 +400,7 @@ public final class FesiEvaluator { | ||||||
| 		"password".equalsIgnoreCase (propname)) | 		"password".equalsIgnoreCase (propname)) | ||||||
| 	    return "[macro access to password property not allowed]"; | 	    return "[macro access to password property not allowed]"; | ||||||
| 
 | 
 | ||||||
| 	// if this is a HopObject, check if the property is defined |                   // if this is a HopObject, check if the property is defined | ||||||
| 	// in the type.properties db-mapping. | 	// in the type.properties db-mapping. | ||||||
| 	if (obj instanceof INode) { | 	if (obj instanceof INode) { | ||||||
| 	    DbMapping dbm = app.getDbMapping (prototypeName); | 	    DbMapping dbm = app.getDbMapping (prototypeName); | ||||||
|  | @ -372,13 +439,37 @@ public final class FesiEvaluator { | ||||||
| 	return app; | 	return app; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      *  Get the object prototype for a prototype name |      * Get a raw prototype, i.e. in potentially unfinished state | ||||||
|  |      * without checking if it needs to be updated. | ||||||
|  |     */ | ||||||
|  |     private ObjectPrototype getRawPrototype (String protoName) { | ||||||
|  |         if (protoName == null) | ||||||
|  |             return null; | ||||||
|  |         TypeInfo info = (TypeInfo) prototypes.get (protoName); | ||||||
|  |         return info == null? null : info.objectPrototype; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      *  Get the object prototype for a prototype name and initialize/update it | ||||||
|  |      *  if necessary. | ||||||
|      */ |      */ | ||||||
|     public ObjectPrototype getPrototype (String protoName) { |     public ObjectPrototype getPrototype (String protoName) { | ||||||
|         if (protoName == null) |         if (protoName == null) | ||||||
|             return null; |             return null; | ||||||
|         return (ObjectPrototype) prototypes.get (protoName); |         TypeInfo info = (TypeInfo) prototypes.get (protoName); | ||||||
|  |         if (info != null && info.lastUpdate == 0) { | ||||||
|  |             Prototype p = app.typemgr.getPrototype (protoName); | ||||||
|  |             if (p != null) { | ||||||
|  |                 app.typemgr.updatePrototype(protoName); | ||||||
|  |                 if (p.getLastUpdate () > info.lastUpdate) { | ||||||
|  |                     info.lastUpdate = p.getLastUpdate (); | ||||||
|  |                     evaluatePrototype(p); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return info == null? null : info.objectPrototype; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -386,7 +477,7 @@ public final class FesiEvaluator { | ||||||
|      */ |      */ | ||||||
|     public void putPrototype (String protoName, ObjectPrototype op) { |     public void putPrototype (String protoName, ObjectPrototype op) { | ||||||
|         if (protoName != null && op != null) |         if (protoName != null && op != null) | ||||||
|             prototypes.put (protoName, op); |             prototypes.put (protoName, new TypeInfo (op, protoName)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -430,7 +521,7 @@ public final class FesiEvaluator { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      *  Get a script wrapper for an implemntation of helma.objectmodel.INode |      *  Get a script wrapper for an instance of helma.objectmodel.INode | ||||||
|      */ |      */ | ||||||
|     public ESNode getNodeWrapper (INode n) { |     public ESNode getNodeWrapper (INode n) { | ||||||
|         // FIXME: should this return ESNull.theNull? |         // FIXME: should this return ESNull.theNull? | ||||||
|  | @ -440,6 +531,7 @@ public final class FesiEvaluator { | ||||||
|         ESNode esn = (ESNode) wrappercache.get (n); |         ESNode esn = (ESNode) wrappercache.get (n); | ||||||
|         if (esn == null || esn.getNode() != n) { |         if (esn == null || esn.getNode() != n) { | ||||||
|             String protoname = n.getPrototype (); |             String protoname = n.getPrototype (); | ||||||
|  | 
 | ||||||
|             ObjectPrototype op = null; |             ObjectPrototype op = null; | ||||||
| 
 | 
 | ||||||
|             // set the DbMapping of the node according to its prototype. |             // set the DbMapping of the node according to its prototype. | ||||||
|  | @ -511,15 +603,11 @@ public final class FesiEvaluator { | ||||||
| 	updateEvaluator (prototype, reader, es); | 	updateEvaluator (prototype, reader, es); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public  synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) { |     private  synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) { | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
| 
 |  | ||||||
|             ObjectPrototype op = getPrototype (prototype.getName()); |             ObjectPrototype op = getPrototype (prototype.getName()); | ||||||
| 
 |  | ||||||
|             // do the update, evaluating the file |             // do the update, evaluating the file | ||||||
|             evaluator.evaluate(reader, op, source, false); |             evaluator.evaluate(reader, op, source, false); | ||||||
| 
 |  | ||||||
|         } catch (Throwable e) { |         } catch (Throwable e) { | ||||||
|             app.logEvent ("Error parsing function file "+source+": "+e); |             app.logEvent ("Error parsing function file "+source+": "+e); | ||||||
|         } finally { |         } finally { | ||||||
|  | @ -532,4 +620,16 @@ public final class FesiEvaluator { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |     class TypeInfo { | ||||||
|  | 
 | ||||||
|  |         ObjectPrototype objectPrototype; | ||||||
|  |         long lastUpdate = 0; | ||||||
|  |         String protoName; | ||||||
|  | 
 | ||||||
|  |         public TypeInfo (ObjectPrototype op, String name) { | ||||||
|  |             objectPrototype = op; | ||||||
|  |             protoName = name; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,85 +0,0 @@ | ||||||
| // 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 final 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(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private FesiEvaluator getEvaluator (RequestEvaluator reval) { |  | ||||||
| 	FesiEvaluator fesi = (FesiEvaluator) evaluators.get (reval); |  | ||||||
| 	if (fesi == null) { |  | ||||||
| 	    fesi = new FesiEvaluator (app, reval); |  | ||||||
| 	    evaluators.put (reval, fesi); |  | ||||||
| 	} |  | ||||||
| 	return fesi; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue