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