Make type handling case-insensitive, change default prototypes to first-letter-upper-case,
do some heavily needed refactoring around helma.scripting.rhino.HopObject and helma.framework.core.TypeManager.
This commit is contained in:
parent
3f284fa899
commit
e57a939fa0
10 changed files with 220 additions and 155 deletions
|
@ -283,7 +283,7 @@ public final class Application implements IPathElement, Runnable {
|
|||
// set the context classloader. Note that this must be done before
|
||||
// using the logging framework so that a new LogFactory gets created
|
||||
// for this app.
|
||||
Thread.currentThread().setContextClassLoader(typemgr.loader);
|
||||
Thread.currentThread().setContextClassLoader(typemgr.getClassLoader());
|
||||
|
||||
if (Server.getServer() != null) {
|
||||
Vector extensions = Server.getServer().getExtensions();
|
||||
|
@ -356,7 +356,7 @@ public final class Application implements IPathElement, Runnable {
|
|||
nmgr = new NodeManager(this, dbDir.getAbsolutePath(), props);
|
||||
|
||||
// reset the classloader to the parent/system/server classloader.
|
||||
Thread.currentThread().setContextClassLoader(typemgr.loader.getParent());
|
||||
Thread.currentThread().setContextClassLoader(typemgr.getClassLoader().getParent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -695,13 +695,15 @@ public final class Application implements IPathElement, Runnable {
|
|||
try {
|
||||
if (classMapping.containsKey("root.factory.class") &&
|
||||
classMapping.containsKey("root.factory.method")) {
|
||||
Class c = typemgr.loader.loadClass(classMapping.getProperty("root.factory.class"));
|
||||
String rootFactory = classMapping.getProperty("root.factory.class");
|
||||
Class c = typemgr.getClassLoader().loadClass(rootFactory);
|
||||
Method m = c.getMethod(classMapping.getProperty("root.factory.method"),
|
||||
null);
|
||||
|
||||
rootObject = m.invoke(c, null);
|
||||
} else {
|
||||
Class c = typemgr.loader.loadClass(classMapping.getProperty("root"));
|
||||
String rootClass = classMapping.getProperty("root");
|
||||
Class c = typemgr.getClassLoader().loadClass(rootClass);
|
||||
|
||||
rootObject = c.newInstance();
|
||||
}
|
||||
|
@ -795,14 +797,14 @@ public final class Application implements IPathElement, Runnable {
|
|||
* Return the prototype with the given name, if it exists
|
||||
*/
|
||||
public Prototype getPrototypeByName(String name) {
|
||||
return (Prototype) typemgr.prototypes.get(name);
|
||||
return typemgr.getPrototype(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collection containing all prototypes defined for this application
|
||||
*/
|
||||
public Collection getPrototypes() {
|
||||
return typemgr.prototypes.values();
|
||||
return typemgr.getPrototypes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1193,7 +1195,7 @@ public final class Application implements IPathElement, Runnable {
|
|||
* Return the application's classloader
|
||||
*/
|
||||
public ClassLoader getClassLoader() {
|
||||
return typemgr.loader;
|
||||
return typemgr.getClassLoader();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -19,6 +19,7 @@ package helma.framework.core;
|
|||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.scripting.*;
|
||||
import helma.util.SystemMap;
|
||||
import helma.util.SystemProperties;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -30,6 +31,7 @@ import java.util.*;
|
|||
*/
|
||||
public final class Prototype {
|
||||
String name;
|
||||
String lowerCaseName;
|
||||
Application app;
|
||||
File directory;
|
||||
File[] files;
|
||||
|
@ -61,15 +63,37 @@ public final class Prototype {
|
|||
/**
|
||||
* Creates a new Prototype object.
|
||||
*
|
||||
* @param name ...
|
||||
* @param dir ...
|
||||
* @param app ...
|
||||
* @param name the prototype's name
|
||||
* @param dir the prototype directory, if known
|
||||
* @param app the application this prototype is a part of
|
||||
*/
|
||||
public Prototype(String name, File dir, Application app) {
|
||||
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
|
||||
this.app = app;
|
||||
this.name = name;
|
||||
this.directory = dir;
|
||||
lowerCaseName = name.toLowerCase();
|
||||
|
||||
if (dir != null) {
|
||||
directory = dir;
|
||||
} else {
|
||||
directory = new File(app.appDir, name);
|
||||
// a little bit of overkill to maintain backwards compatibility
|
||||
// with lower case type names...
|
||||
if (!directory.isDirectory()) {
|
||||
File lowerDir = new File(app.appDir, lowerCaseName);
|
||||
if (lowerDir.isDirectory()) {
|
||||
directory = lowerDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and register type properties file
|
||||
File propfile = new File(directory, "type.properties");
|
||||
SystemProperties props = new SystemProperties(propfile.getAbsolutePath());
|
||||
dbmap = new DbMapping(app, name, props);
|
||||
// we don't need to put the DbMapping into proto.updatables, because
|
||||
// dbmappings are checked separately in TypeManager.checkFiles() for
|
||||
// each request
|
||||
|
||||
code = new HashMap();
|
||||
zippedCode = new HashMap();
|
||||
|
@ -145,7 +169,7 @@ public final class Prototype {
|
|||
*/
|
||||
public void setParentPrototype(Prototype parent) {
|
||||
// this is not allowed for the hopobject and global prototypes
|
||||
if ("hopobject".equalsIgnoreCase(name) || "global".equalsIgnoreCase(name)) {
|
||||
if ("HopObject".equals(name) || "global".equals(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -164,11 +188,11 @@ public final class Prototype {
|
|||
* Check if the given prototype is within this prototype's parent chain.
|
||||
*/
|
||||
public final boolean isInstanceOf(String pname) {
|
||||
if (name.equals(pname)) {
|
||||
if (name.equals(pname) || lowerCaseName.equals(pname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((parent != null) && !"hopobject".equalsIgnoreCase(parent.getName())) {
|
||||
if ((parent != null) && !"HopObject".equals(parent.getName())) {
|
||||
return parent.isInstanceOf(pname);
|
||||
}
|
||||
|
||||
|
@ -185,12 +209,17 @@ public final class Prototype {
|
|||
|
||||
Prototype p = parent;
|
||||
|
||||
while ((p != null) && !"hopobject".equalsIgnoreCase(p.getName())) {
|
||||
while ((p != null) && !"hopobject".equals(p.getLowerCaseName())) {
|
||||
Object old = handlers.put(p.name, obj);
|
||||
// if an object was already registered by this name, put it back in again.
|
||||
if (old != null) {
|
||||
handlers.put(p.name, old);
|
||||
}
|
||||
// same with lower case name
|
||||
old = handlers.put(p.lowerCaseName, obj);
|
||||
if (old != null) {
|
||||
handlers.put(p.lowerCaseName, old);
|
||||
}
|
||||
|
||||
p = p.parent;
|
||||
}
|
||||
|
@ -201,7 +230,7 @@ public final class Prototype {
|
|||
*
|
||||
* @param dbmap ...
|
||||
*/
|
||||
public void setDbMapping(DbMapping dbmap) {
|
||||
protected void setDbMapping(DbMapping dbmap) {
|
||||
this.dbmap = dbmap;
|
||||
}
|
||||
|
||||
|
@ -245,7 +274,7 @@ public final class Prototype {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Return this prototype's name
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
|
@ -253,6 +282,15 @@ public final class Prototype {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this prototype's name in lower case letters
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
public String getLowerCaseName() {
|
||||
return lowerCaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last time any script has been re-read for this prototype.
|
||||
*/
|
||||
|
|
|
@ -294,6 +294,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
// immediately register objects with their direct prototype name
|
||||
if (protos[i] != null) {
|
||||
macroHandlers.put(protos[i].getName(), obj);
|
||||
macroHandlers.put(protos[i].getLowerCaseName(), obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ public class RequestPath {
|
|||
|
||||
if (proto != null) {
|
||||
primaryProtos.put(proto.getName(), obj);
|
||||
primaryProtos.put(proto.getLowerCaseName(), obj);
|
||||
proto.registerParents(secondaryProtos, obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -412,7 +412,7 @@ public final class Skin {
|
|||
// not a global macro - need to find handler object
|
||||
// was called with this object - check it or its parents for matching prototype
|
||||
if (!handler.equals("this") &&
|
||||
!handler.equals(app.getPrototypeName(thisObject))) {
|
||||
!handler.equalsIgnoreCase(app.getPrototypeName(thisObject))) {
|
||||
// the handler object is not what we want
|
||||
Object n = thisObject;
|
||||
|
||||
|
|
|
@ -30,30 +30,34 @@ import java.util.*;
|
|||
* applications and updates the evaluators if anything has changed.
|
||||
*/
|
||||
public final class TypeManager {
|
||||
final static String[] standardTypes = { "user", "global", "root", "hopobject" };
|
||||
final static String[] standardTypes = { "User", "Global", "Root", "HopObject" };
|
||||
final static String templateExtension = ".hsp";
|
||||
final static String scriptExtension = ".js";
|
||||
final static String actionExtension = ".hac";
|
||||
final static String skinExtension = ".skin";
|
||||
Application app;
|
||||
File appDir;
|
||||
HashMap prototypes; // map of prototypes
|
||||
HashMap zipfiles; // map of zipped script files
|
||||
HashSet jarfiles; // set of Java archives
|
||||
long lastCheck = 0;
|
||||
long appDirMod = 0;
|
||||
|
||||
private Application app;
|
||||
private File appDir;
|
||||
// map of prototypes
|
||||
private HashMap prototypes;
|
||||
// map of zipped script files
|
||||
private HashMap zipfiles;
|
||||
// set of Java archives
|
||||
private HashSet jarfiles;
|
||||
private long lastCheck = 0;
|
||||
private long appDirMod = 0;
|
||||
|
||||
// a checksum that changes whenever something in the application files changes.
|
||||
long checksum;
|
||||
private long checksum;
|
||||
|
||||
// the hopobject prototype
|
||||
Prototype hopobjectProto;
|
||||
// private Prototype hopobjectProto;
|
||||
|
||||
// the global prototype
|
||||
Prototype globalProto;
|
||||
// private Prototype globalProto;
|
||||
|
||||
// app specific class loader, includes jar files in the app directory
|
||||
AppClassLoader loader;
|
||||
private AppClassLoader loader;
|
||||
|
||||
/**
|
||||
* Creates a new TypeManager object.
|
||||
|
@ -114,13 +118,9 @@ public final class TypeManager {
|
|||
*/
|
||||
public void createPrototypes() {
|
||||
// create standard prototypes.
|
||||
createPrototype("root");
|
||||
createPrototype("user");
|
||||
|
||||
// get references to hopobject and global protos,
|
||||
// since we need it regularly when setting parent prototypes.
|
||||
hopobjectProto = createPrototype("hopobject");
|
||||
globalProto = createPrototype("global");
|
||||
for (int i = 0; i < standardTypes.length; i++) {
|
||||
createPrototype(standardTypes[i], null);
|
||||
}
|
||||
|
||||
// loop through directories and create prototypes
|
||||
checkFiles();
|
||||
|
@ -236,19 +236,12 @@ public final class TypeManager {
|
|||
DbMapping dbmap = proto.getDbMapping();
|
||||
|
||||
if ((dbmap != null) && dbmap.needsUpdate()) {
|
||||
// call dbmap.update(). This also checks the
|
||||
// parent prototype for prototypes other than
|
||||
// global and HopObject, which is a bit awkward...
|
||||
// I mean we're the type manager, so this should
|
||||
// be part of our job, right?
|
||||
dbmap.update();
|
||||
|
||||
// this is now done in dbmap.update()!!!
|
||||
/*if ((proto != hopobjectProto) && (proto != globalProto)) {
|
||||
// set parent prototype, in case it has changed.
|
||||
String parentName = dbmap.getExtends();
|
||||
|
||||
if (parentName != null) {
|
||||
proto.setParentPrototype(getPrototype(parentName));
|
||||
} else if (!app.isJavaPrototype(proto.getName())) {
|
||||
proto.setParentPrototype(hopobjectProto);
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,40 +285,48 @@ public final class TypeManager {
|
|||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class loader used by this application.
|
||||
*
|
||||
* @return the ClassLoader
|
||||
*/
|
||||
public ClassLoader getClassLoader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collection containing the prototypes defined for this type
|
||||
* manager.
|
||||
*
|
||||
* @return a collection containing the prototypes
|
||||
*/
|
||||
public Collection getPrototypes() {
|
||||
return prototypes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prototype defined for this application
|
||||
*/
|
||||
public Prototype getPrototype(String typename) {
|
||||
return (Prototype) prototypes.get(typename);
|
||||
if (typename == null) {
|
||||
return null;
|
||||
}
|
||||
return (Prototype) prototypes.get(typename.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prototype, creating it if it doesn't already exist. Note
|
||||
* that it doesn't create a DbMapping - this is left to the
|
||||
* caller (e.g. ZippedAppFile).
|
||||
*/
|
||||
public Prototype createPrototype(String typename) {
|
||||
return createPrototype(typename, new File(appDir, typename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a prototype from a directory containing scripts and other stuff
|
||||
* Create and register a new Prototype.
|
||||
*
|
||||
* @param typename the name of the prototype
|
||||
* @param dir the prototype directory if it is know, or null if we
|
||||
* ought to find out by ourselves
|
||||
* @return the newly created prototype
|
||||
*/
|
||||
public Prototype createPrototype(String typename, File dir) {
|
||||
Prototype proto = new Prototype(typename, dir, app);
|
||||
|
||||
// Create and register type properties file
|
||||
File propfile = new File(dir, "type.properties");
|
||||
SystemProperties props = new SystemProperties(propfile.getAbsolutePath());
|
||||
DbMapping dbmap = new DbMapping(app, typename, props);
|
||||
|
||||
// we don't need to put the DbMapping into proto.updatables, because
|
||||
// dbmappings are checked separately in checkFiles for each request
|
||||
// proto.updatables.put ("type.properties", dbmap);
|
||||
proto.setDbMapping(dbmap);
|
||||
|
||||
// put the prototype into our map
|
||||
prototypes.put(typename, proto);
|
||||
prototypes.put(proto.getLowerCaseName(), proto);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ZippedAppFile implements Updatable {
|
|||
Prototype proto = app.typemgr.getPrototype(dir);
|
||||
|
||||
if (proto == null) {
|
||||
proto = app.typemgr.createPrototype(dir);
|
||||
proto = app.typemgr.createPrototype(dir, null);
|
||||
newPrototypes.add(proto);
|
||||
}
|
||||
|
||||
|
|
|
@ -505,7 +505,7 @@ public final class Node implements INode, Serializable {
|
|||
public String getPrototype() {
|
||||
// if prototype is null, it's a vanilla HopObject.
|
||||
if (prototype == null) {
|
||||
return "hopobject";
|
||||
return "HopObject";
|
||||
}
|
||||
|
||||
return prototype;
|
||||
|
|
|
@ -78,6 +78,35 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
setPrototype(proto);
|
||||
}
|
||||
|
||||
public static HopObject init(Scriptable scope)
|
||||
throws PropertyException {
|
||||
int attributes = READONLY | DONTENUM | PERMANENT;
|
||||
|
||||
// create prototype object
|
||||
HopObject proto = new HopObject();
|
||||
proto.setPrototype(getObjectPrototype(scope));
|
||||
|
||||
// install JavaScript methods and properties
|
||||
Method[] methods = HopObject.class.getDeclaredMethods();
|
||||
for (int i=0; i<methods.length; i++) {
|
||||
String methodName = methods[i].getName();
|
||||
|
||||
if (methodName.startsWith("jsFunction_")) {
|
||||
methodName = methodName.substring(11);
|
||||
FunctionObject func = new FunctionObject(methodName,
|
||||
methods[i], proto);
|
||||
proto.defineProperty(methodName, func, attributes);
|
||||
|
||||
} else if (methodName.startsWith("jsGet_")) {
|
||||
methodName = methodName.substring(6);
|
||||
proto.defineProperty(methodName, null, methods[i],
|
||||
null, attributes);
|
||||
}
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is used as HopObject constructor from JavaScript.
|
||||
*/
|
||||
|
@ -408,14 +437,18 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
/**
|
||||
* Prefetch child objects from (relational) database.
|
||||
*/
|
||||
public void jsFunction_prefetchChildren() {
|
||||
jsFunction_prefetchChildren(0, 1000);
|
||||
public void jsFunction_prefetchChildren(Object startArg, Object lengthArg) {
|
||||
// check if we were called with no arguments
|
||||
if (startArg == Undefined.instance && lengthArg == Undefined.instance) {
|
||||
prefetchChildren(0, 1000);
|
||||
} else {
|
||||
int start = (int) ScriptRuntime.toNumber(startArg);
|
||||
int length = (int) ScriptRuntime.toNumber(lengthArg);
|
||||
prefetchChildren(start, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch child objects from (relational) database.
|
||||
*/
|
||||
public void jsFunction_prefetchChildren(int start, int length) {
|
||||
private void prefetchChildren(int start, int length) {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
return;
|
||||
}
|
||||
|
@ -424,7 +457,8 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
|
||||
try {
|
||||
((helma.objectmodel.db.Node) node).prefetchChildren(start, length);
|
||||
} catch (Exception x) {
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error in HopObject.prefetchChildren(): "+ignore);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,6 +480,7 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
private Scriptable list() {
|
||||
checkNode();
|
||||
|
||||
prefetchChildren(0, 1000);
|
||||
Enumeration e = node.getSubnodes();
|
||||
ArrayList a = new ArrayList();
|
||||
|
||||
|
@ -475,7 +510,7 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
|
||||
checkNode();
|
||||
|
||||
jsFunction_prefetchChildren(start, length);
|
||||
prefetchChildren(start, length);
|
||||
ArrayList a = new ArrayList();
|
||||
|
||||
for (int i=start; i<start+length; i++) {
|
||||
|
@ -706,7 +741,7 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
|||
* @return ...
|
||||
*/
|
||||
public Object get(String name, Scriptable start) {
|
||||
// System.err.println ("GET from "+node+": "+name);
|
||||
// System.err.println("GET from "+this+": "+name+" ->"+super.get(name, start));
|
||||
Object retval = null;
|
||||
|
||||
if (node == null) {
|
||||
|
|
|
@ -51,6 +51,9 @@ public final class RhinoCore {
|
|||
// the wrap factory
|
||||
WrapFactory wrapper;
|
||||
|
||||
// the prototype for HopObject
|
||||
ScriptableObject hopObjectProto;
|
||||
|
||||
// the prototype for path objects
|
||||
PathWrapper pathProto;
|
||||
|
||||
|
@ -90,21 +93,15 @@ public final class RhinoCore {
|
|||
|
||||
global = (GlobalObject) context.initStandardObjects(g);
|
||||
|
||||
ScriptableObject.defineClass(global, HopObject.class);
|
||||
ScriptableObject.defineClass(global, FileObject.class);
|
||||
ScriptableObject.defineClass(global, FtpObject.class);
|
||||
|
||||
pathProto = new PathWrapper(this);
|
||||
|
||||
hopObjectProto = HopObject.init(global);
|
||||
FileObject.init(global);
|
||||
FtpObject.init(global);
|
||||
ImageObject.init(global);
|
||||
XmlRpcObject.init(global);
|
||||
MailObject.init(global, app.getProperties());
|
||||
|
||||
registerPrototype("hopobject",
|
||||
(ScriptableObject) ScriptableObject
|
||||
.getClassPrototype(global, "HopObject"));
|
||||
registerPrototype("global", global);
|
||||
|
||||
// add some convenience functions to string, date and number prototypes
|
||||
Scriptable stringProto = ScriptableObject.getClassPrototype(global, "String");
|
||||
stringProto.put("trim", stringProto, new StringTrim());
|
||||
|
@ -150,33 +147,34 @@ public final class RhinoCore {
|
|||
*
|
||||
* @param prototype the prototype to be created
|
||||
*/
|
||||
synchronized void initPrototype(Prototype prototype) {
|
||||
synchronized TypeInfo initPrototype(Prototype prototype) {
|
||||
|
||||
String name = prototype.getName();
|
||||
String lowerCaseName = prototype.getLowerCaseName();
|
||||
|
||||
TypeInfo type = (TypeInfo) prototypes.get(lowerCaseName);
|
||||
|
||||
// check if the prototype info exists already
|
||||
ScriptableObject op = getRawPrototype(name);
|
||||
ScriptableObject op = (type == null) ? null : type.objectPrototype;
|
||||
|
||||
// if prototype info doesn't exist (i.e. is a standard prototype
|
||||
// built by HopExtension), create it.
|
||||
if (op == null) {
|
||||
try {
|
||||
if ("global".equals(lowerCaseName)) {
|
||||
op = global;
|
||||
} else if ("hopobject".equals(lowerCaseName)) {
|
||||
op = hopObjectProto;
|
||||
} else {
|
||||
op = new HopObject(name);
|
||||
op.setParentScope(global);
|
||||
// op.put("prototypename", op, name);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error creating prototype: " + ignore);
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
registerPrototype(name, op);
|
||||
type = registerPrototype(prototype, op);
|
||||
}
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a new prototyped hopobject and then calls
|
||||
// This will first create a new prototyped HopObject and then calls
|
||||
// the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase(name) &&
|
||||
!"root".equalsIgnoreCase(name) &&
|
||||
!"hopobject".equalsIgnoreCase(name)) {
|
||||
if (!"global".equals(lowerCaseName)) {
|
||||
try {
|
||||
installConstructor(name, op);
|
||||
} catch (Exception ignore) {
|
||||
|
@ -184,18 +182,20 @@ public final class RhinoCore {
|
|||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a prototype, parsing and compiling all its script files.
|
||||
*
|
||||
* @param prototype the prototype to update/evaluate/compile
|
||||
* @param type the info, containing the object proto, last update time and
|
||||
* the set of compiled functions properties
|
||||
*/
|
||||
synchronized void evaluatePrototype(Prototype prototype, TypeInfo type) {
|
||||
// System.err.println("EVALUATING PROTO: "+prototype);
|
||||
synchronized void evaluatePrototype(TypeInfo type) {
|
||||
|
||||
Scriptable op = type.objectPrototype;
|
||||
Prototype prototype = type.frameworkPrototype;
|
||||
|
||||
// set the parent prototype in case it hasn't been done before
|
||||
// or it has changed...
|
||||
|
@ -258,8 +258,9 @@ public final class RhinoCore {
|
|||
*/
|
||||
private void setParentPrototype(Prototype prototype, Scriptable op) {
|
||||
String name = prototype.getName();
|
||||
String lowerCaseName = prototype.getLowerCaseName();
|
||||
|
||||
if (!"global".equalsIgnoreCase(name) && !"hopobject".equalsIgnoreCase(name)) {
|
||||
if (!"global".equals(lowerCaseName) && !"hopobject".equals(lowerCaseName)) {
|
||||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
Scriptable opp = null;
|
||||
|
@ -282,12 +283,12 @@ public final class RhinoCore {
|
|||
/**
|
||||
* This is a version of org.mozilla.javascript.FunctionObject.addAsConstructor()
|
||||
* that does not set the constructor property in the prototype. This is because
|
||||
* we want our own scripted constructor function to prevail, if it is defined.
|
||||
* we want our own scripted constructor function to be visible, if it is defined.
|
||||
*
|
||||
* @param name the name of the constructor
|
||||
* @param op the object prototype
|
||||
*/
|
||||
private void installConstructor(String name, Scriptable op) {
|
||||
void installConstructor(String name, Scriptable op) {
|
||||
FunctionObject fo = new FunctionObject(name, HopObject.hopObjCtor, global);
|
||||
|
||||
ScriptRuntime.setFunctionProtoAndParent(global, fo);
|
||||
|
@ -315,27 +316,23 @@ public final class RhinoCore {
|
|||
|
||||
for (Iterator i = protos.iterator(); i.hasNext();) {
|
||||
Prototype proto = (Prototype) i.next();
|
||||
TypeInfo type = (TypeInfo) prototypes.get(proto.getName());
|
||||
TypeInfo type = (TypeInfo) prototypes.get(proto.getLowerCaseName());
|
||||
|
||||
if (type == null) {
|
||||
// a prototype we don't know anything about yet. Init local update info.
|
||||
initPrototype(proto);
|
||||
type = (TypeInfo) prototypes.get(proto.getName());
|
||||
type = initPrototype(proto);
|
||||
}
|
||||
|
||||
// only update prototype if it has already been initialized.
|
||||
// otherwise, this will be done on demand
|
||||
// System.err.println ("CHECKING PROTO "+proto+": "+type);
|
||||
if (type.lastUpdate > -1) {
|
||||
Prototype p = app.typemgr.getPrototype(type.protoName);
|
||||
// let the type manager scan the prototype's directory
|
||||
app.typemgr.updatePrototype(proto);
|
||||
|
||||
if (p != null) {
|
||||
// System.err.println ("UPDATING PROTO: "+p);
|
||||
app.typemgr.updatePrototype(p);
|
||||
|
||||
if (p.getLastUpdate() > type.lastUpdate) {
|
||||
evaluatePrototype(p, type);
|
||||
}
|
||||
// and re-evaluate if necessary
|
||||
if (type.needsUpdate()) {
|
||||
evaluatePrototype(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -343,19 +340,6 @@ public final class RhinoCore {
|
|||
lastUpdate = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a raw prototype, i.e. in potentially unfinished state
|
||||
* without checking if it needs to be updated.
|
||||
*/
|
||||
private ScriptableObject getRawPrototype(String protoName) {
|
||||
if (protoName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInfo type = (TypeInfo) prototypes.get(protoName);
|
||||
|
||||
return (type == null) ? null : type.objectPrototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of getPrototype() that retrieves a prototype and checks
|
||||
|
@ -394,20 +378,16 @@ public final class RhinoCore {
|
|||
return null;
|
||||
}
|
||||
|
||||
TypeInfo type = (TypeInfo) prototypes.get(protoName);
|
||||
TypeInfo type = (TypeInfo) prototypes.get(protoName.toLowerCase());
|
||||
|
||||
// if type exists and hasn't been evaluated (used) yet, evaluate it now.
|
||||
// otherwise, it has already been evaluated for this request by updatePrototypes(),
|
||||
// which is called before a request is handled.
|
||||
if ((type != null) && (type.lastUpdate == -1)) {
|
||||
Prototype p = app.typemgr.getPrototype(protoName);
|
||||
app.typemgr.updatePrototype(type.frameworkPrototype);
|
||||
|
||||
if (p != null) {
|
||||
app.typemgr.updatePrototype(p);
|
||||
|
||||
if (p.getLastUpdate() > type.lastUpdate) {
|
||||
evaluatePrototype(p, type);
|
||||
}
|
||||
if (type.needsUpdate()) {
|
||||
evaluatePrototype(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,10 +397,10 @@ public final class RhinoCore {
|
|||
/**
|
||||
* Register an object prototype for a prototype name.
|
||||
*/
|
||||
private void registerPrototype(String protoName, ScriptableObject op) {
|
||||
if ((protoName != null) && (op != null)) {
|
||||
prototypes.put(protoName, new TypeInfo(op, protoName));
|
||||
}
|
||||
private TypeInfo registerPrototype(Prototype proto, ScriptableObject op) {
|
||||
TypeInfo type = new TypeInfo(proto, op);
|
||||
prototypes.put(proto.getLowerCaseName(), type);
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -561,8 +541,8 @@ public final class RhinoCore {
|
|||
Scriptable op = getPrototype(prototypeName);
|
||||
|
||||
if (op == null) {
|
||||
prototypeName = "hopobject";
|
||||
op = getPrototype("hopobject");
|
||||
prototypeName = "HopObject";
|
||||
op = getPrototype("HopObject");
|
||||
}
|
||||
|
||||
w = new JavaObject(global, e, prototypeName, op, this);
|
||||
|
@ -602,8 +582,8 @@ public final class RhinoCore {
|
|||
|
||||
// no prototype found for this node?
|
||||
if (op == null) {
|
||||
op = getValidPrototype("hopobject");
|
||||
protoname = "hopobject";
|
||||
op = getValidPrototype("HopObject");
|
||||
protoname = "HopObject";
|
||||
}
|
||||
|
||||
esn = new HopObject(protoname, op);
|
||||
|
@ -797,7 +777,7 @@ public final class RhinoCore {
|
|||
}
|
||||
// mark prototype as broken
|
||||
if (type.error == null && e instanceof EcmaError) {
|
||||
if ("global".equals(type.protoName)) {
|
||||
if ("global".equals(type.frameworkPrototype.getLowerCaseName())) {
|
||||
globalError = (EcmaError) e;
|
||||
} else {
|
||||
type.error = (EcmaError) e;
|
||||
|
@ -828,7 +808,10 @@ public final class RhinoCore {
|
|||
*/
|
||||
class TypeInfo {
|
||||
|
||||
// the object prototype for this type
|
||||
// the framework prototype object
|
||||
Prototype frameworkPrototype;
|
||||
|
||||
// the JavaScript prototype for this type
|
||||
ScriptableObject objectPrototype;
|
||||
|
||||
// timestamp of last update. This is -1 so even an empty prototype directory
|
||||
|
@ -837,7 +820,7 @@ public final class RhinoCore {
|
|||
long lastUpdate = -1;
|
||||
|
||||
// the prototype name
|
||||
String protoName;
|
||||
// String protoName;
|
||||
|
||||
// a set of property values that were defined in last script compliation
|
||||
Set compiledFunctions;
|
||||
|
@ -847,9 +830,9 @@ public final class RhinoCore {
|
|||
|
||||
EcmaError error;
|
||||
|
||||
public TypeInfo(ScriptableObject op, String name) {
|
||||
public TypeInfo(Prototype proto, ScriptableObject op) {
|
||||
frameworkPrototype = proto;
|
||||
objectPrototype = op;
|
||||
protoName = name;
|
||||
compiledFunctions = new HashSet(0);
|
||||
// remember properties already defined on this object prototype
|
||||
predefinedProperties = new HashSet();
|
||||
|
@ -859,8 +842,12 @@ public final class RhinoCore {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean needsUpdate() {
|
||||
return frameworkPrototype.getLastUpdate() > lastUpdate;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("TypeInfo[" + protoName + "," + new Date(lastUpdate) + "]");
|
||||
return ("TypeInfo[" + frameworkPrototype + "," + new Date(lastUpdate) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue