diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java index 280fa9d6..79cc699e 100644 --- a/src/helma/framework/core/Application.java +++ b/src/helma/framework/core/Application.java @@ -984,6 +984,23 @@ public final class Application implements Runnable { return typemgr.getPrototypes(); } + /** + * Programmatically define a new prototype. If a prototype with this name already exists return + * the existing prototype. + * @param name the prototype name + * @param typeProps custom type properties map + * @return the new prototype + */ + public Prototype definePrototype(String name, Map typeProps) { + Prototype proto = typemgr.getPrototype(name); + if (proto == null) { + proto = typemgr.createPrototype(name, null, typeProps); + } else { + proto.setTypeProperties(typeProps); + } + return proto; + } + /** * Return a skin for a given object. The skin is found by determining the prototype * to use for the object, then looking up the skin for the prototype. diff --git a/src/helma/framework/core/Prototype.java b/src/helma/framework/core/Prototype.java index 126db96b..17d5994c 100644 --- a/src/helma/framework/core/Prototype.java +++ b/src/helma/framework/core/Prototype.java @@ -74,8 +74,9 @@ public final class Prototype { * @param name the prototype's name * @param repository the first prototype's repository * @param app the application this prototype is a part of + * @param typeProps custom type mapping properties */ - public Prototype(String name, Repository repository, Application app) { + public Prototype(String name, Repository repository, Application app, Map typeProps) { // app.logEvent ("Constructing Prototype "+app.getName()+"/"+name); this.app = app; this.name = name; @@ -87,10 +88,13 @@ public final class Prototype { // Create and register type properties file props = new ResourceProperties(app); - if (repository != null) { + if (typeProps != null) { + props.putAll(typeProps); + } else if (repository != null) { props.addResource(repository.getResource("type.properties")); props.addResource(repository.getResource(name + ".properties")); } + 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 @@ -392,6 +396,16 @@ public final class Prototype { lastCodeUpdate = System.currentTimeMillis(); } + /** + * Set the custom type properties for this prototype and update the database mapping. + * @param map the custom type mapping properties. + */ + public void setTypeProperties(Map map) { + props.clear(); + props.putAll(map); + dbmap.update(); + } + /** * Get the prototype's aggregated type.properties * diff --git a/src/helma/framework/core/TypeManager.java b/src/helma/framework/core/TypeManager.java index d6696c28..b982ac09 100644 --- a/src/helma/framework/core/TypeManager.java +++ b/src/helma/framework/core/TypeManager.java @@ -104,7 +104,7 @@ public final class TypeManager { public synchronized void createPrototypes() throws IOException { // create standard prototypes. for (int i = 0; i < standardTypes.length; i++) { - createPrototype(standardTypes[i], null); + createPrototype(standardTypes[i], null, null); } // loop through directories and create prototypes @@ -154,7 +154,7 @@ public final class TypeManager { if (proto == null) { // create new prototype if type name is valid if (isValidTypeName(name)) - createPrototype(name, list[i]); + createPrototype(name, list[i], null); } else { proto.addRepository(list[i], update); } @@ -294,14 +294,15 @@ public final class TypeManager { * * @param typename the name of the prototype * @param repository the first prototype source + * @param typeProps custom type mapping properties * @return the newly created prototype */ - public synchronized Prototype createPrototype(String typename, Repository repository) { + public synchronized Prototype createPrototype(String typename, Repository repository, Map typeProps) { if ("true".equalsIgnoreCase(app.getProperty("helma.debugTypeManager"))) { System.err.println("CREATE: " + typename + " from " + repository + " in " + Thread.currentThread()); // Thread.dumpStack(); } - Prototype proto = new Prototype(typename, repository, app); + Prototype proto = new Prototype(typename, repository, app, typeProps); // put the prototype into our map prototypes.put(proto.getLowerCaseName(), proto); return proto; diff --git a/src/helma/scripting/rhino/GlobalObject.java b/src/helma/scripting/rhino/GlobalObject.java index c39e77a4..341c0a1e 100644 --- a/src/helma/scripting/rhino/GlobalObject.java +++ b/src/helma/scripting/rhino/GlobalObject.java @@ -73,7 +73,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { "getXmlDocument", "getHtmlDocument", "seal", "getDBConnection", "getURL", "write", "writeln", "serialize", "deserialize", "defineLibraryScope", - "wrapJavaMap", "unwrapJavaMap", "toJava" + "wrapJavaMap", "unwrapJavaMap", "toJava", "definePrototype" }; defineFunctionProperties(globalFuncs, GlobalObject.class, DONTENUM | PERMANENT); @@ -673,6 +673,24 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { return null; } + public Object definePrototype(String name, Scriptable desc) { + if (name == null) { + throw new IllegalArgumentException("First argument to definePrototype() must be String"); + } + if (desc == null) { + throw new IllegalArgumentException("Second argument to definePrototype() must be Object"); + } + + Prototype proto = core.app.definePrototype(name, core.scriptableToProperties(desc)); + RhinoCore.TypeInfo type = (RhinoCore.TypeInfo) core.prototypes.get(proto.getLowerCaseName()); + if (type == null) { + type = core.initPrototype(proto); + } + core.setParentPrototype(proto, type); + return type.objProto; + } + + private static String toString(Object obj) { if (obj == null || obj == Undefined.instance) { // Note: we might return "" here in order