Add static getCollection() method on HopObject constructors to generate collections programmatically and on the fly. Implement limit and offset collection properties for databases that support it (Postgresql + Mysql)
This commit is contained in:
		
							parent
							
								
									0a62df7875
								
							
						
					
					
						commit
						a32b4f2c86
					
				
					 4 changed files with 242 additions and 104 deletions
				
			
		|  | @ -36,7 +36,7 @@ public final class DbMapping { | |||
|     private final String typename; | ||||
| 
 | ||||
|     // properties from where the mapping is read | ||||
|     private final ResourceProperties props; | ||||
|     private final Properties props; | ||||
| 
 | ||||
|     // name of data dbSource to which this mapping writes | ||||
|     private DbSource dbSource; | ||||
|  | @ -147,7 +147,7 @@ public final class DbMapping { | |||
|     /** | ||||
|      * Create a DbMapping from a type.properties property file | ||||
|      */ | ||||
|     public DbMapping(Application app, String typename, ResourceProperties props) { | ||||
|     public DbMapping(Application app, String typename, Properties props) { | ||||
|         this.app = app; | ||||
|         // create a unique instance of the string. This is useful so | ||||
|         // we can compare types just by using == instead of equals. | ||||
|  | @ -169,7 +169,10 @@ public final class DbMapping { | |||
|      * Tell the type manager whether we need update() to be called | ||||
|      */ | ||||
|     public boolean needsUpdate() { | ||||
|         return props.lastModified() != lastTypeChange; | ||||
|         if (props instanceof ResourceProperties) { | ||||
|             return ((ResourceProperties) props).lastModified() != lastTypeChange; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -233,7 +236,8 @@ public final class DbMapping { | |||
|             parentInfo = null; | ||||
|         } | ||||
| 
 | ||||
|         lastTypeChange = props.lastModified(); | ||||
|         lastTypeChange = props instanceof ResourceProperties ? | ||||
|                 ((ResourceProperties) props).lastModified() : System.currentTimeMillis(); | ||||
| 
 | ||||
|         // see if this prototype extends (inherits from) any other prototype | ||||
|         String extendsProto = props.getProperty("_extends"); | ||||
|  | @ -298,13 +302,15 @@ public final class DbMapping { | |||
|         HashMap d2p = new HashMap(); | ||||
|         ArrayList joinList = new ArrayList(); | ||||
| 
 | ||||
|         for (Enumeration e = props.keys(); e.hasMoreElements();) { | ||||
|             String propName = (String) e.nextElement(); | ||||
|         for (Iterator it = props.entrySet().iterator(); it.hasNext(); ) { | ||||
|             Map.Entry entry =  (Map.Entry) it.next(); | ||||
| 
 | ||||
|             try { | ||||
|                 String propName = (String) entry.getKey(); | ||||
| 
 | ||||
|                 // ignore internal properties (starting with "_") and sub-options (containing a ".") | ||||
|                 if (!propName.startsWith("_") && (propName.indexOf(".") < 0)) { | ||||
|                     String dbField = props.getProperty(propName); | ||||
|                     Object propValue = entry.getValue(); | ||||
| 
 | ||||
|                     // check if a relation for this propery already exists. If so, reuse it | ||||
|                     Relation rel = (Relation) prop2db.get(propName); | ||||
|  | @ -313,7 +319,7 @@ public final class DbMapping { | |||
|                         rel = new Relation(propName, this); | ||||
|                     } | ||||
| 
 | ||||
|                     rel.update(dbField, props); | ||||
|                     rel.update(propValue, getSubProperties(propName)); | ||||
|                     p2d.put(propName, rel); | ||||
| 
 | ||||
|                     if ((rel.columnName != null) && rel.isPrimitiveOrReference()) { | ||||
|  | @ -354,7 +360,7 @@ public final class DbMapping { | |||
|         joins = new Relation[joinList.size()]; | ||||
|         joins = (Relation[]) joinList.toArray(joins); | ||||
| 
 | ||||
|         String subnodeMapping = props.getProperty("_children"); | ||||
|         Object subnodeMapping = props.get("_children"); | ||||
| 
 | ||||
|         if (subnodeMapping != null) { | ||||
|             try { | ||||
|  | @ -363,7 +369,7 @@ public final class DbMapping { | |||
|                     subRelation = new Relation("_children", this); | ||||
|                 } | ||||
| 
 | ||||
|                 subRelation.update(subnodeMapping, props); | ||||
|                 subRelation.update(subnodeMapping, getSubProperties("_children")); | ||||
| 
 | ||||
|                 // if subnodes are accessed via access name or group name, | ||||
|                 // the subnode relation is also the property relation. | ||||
|  | @ -396,6 +402,9 @@ public final class DbMapping { | |||
|      */ | ||||
|     private void registerExtension(String extID, String extName) { | ||||
|         // lazy initialization of extensionMap | ||||
|         if (extID == null) { | ||||
|             return; | ||||
|         } | ||||
|         if (extensionMap == null) { | ||||
|             extensionMap = new ResourceProperties(); | ||||
|             extensionMap.setIgnoreCase(true); | ||||
|  | @ -1469,10 +1478,31 @@ public final class DbMapping { | |||
|      * | ||||
|      * @return our properties | ||||
|      */ | ||||
|     public ResourceProperties getProperties() { | ||||
|     public Properties getProperties() { | ||||
|         return props; | ||||
|     } | ||||
| 
 | ||||
|     public Properties getSubProperties(String prefix) { | ||||
|         if (props.get(prefix) instanceof Properties) { | ||||
|             return (Properties) props.get(prefix); | ||||
|         } else if (props instanceof ResourceProperties) { | ||||
|             return ((ResourceProperties) props).getSubProperties(prefix + "."); | ||||
|         } else { | ||||
|             Properties subprops = new Properties(); | ||||
|             prefix = prefix + "."; | ||||
|             Iterator it = props.entrySet().iterator(); | ||||
|             int prefixLength = prefix.length(); | ||||
|             while (it.hasNext()) { | ||||
|                 Map.Entry entry = (Map.Entry) it.next(); | ||||
|                 String key = entry.getKey().toString(); | ||||
|                 if (key.regionMatches(false, 0, prefix, 0, prefixLength)) { | ||||
|                     subprops.put(key.substring(prefixLength), entry.getValue()); | ||||
|                 } | ||||
|             } | ||||
|             return subprops; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Register a DbMapping that depends on this DbMapping, so that collections of other mapping | ||||
|      * should be reloaded if data on this mapping is updated. | ||||
|  |  | |||
|  | @ -102,6 +102,7 @@ public final class Relation { | |||
|     Vector filterFragments; | ||||
|     Vector filterPropertyRefs; | ||||
|     int maxSize = 0; | ||||
|     int offset = 0; | ||||
| 
 | ||||
|     /** | ||||
|      * This constructor makes a copy of an existing relation. Not all fields are copied, just those | ||||
|  | @ -123,6 +124,7 @@ public final class Relation { | |||
|         this.additionalTablesJoined =   rel.additionalTablesJoined; | ||||
|         this.queryHints =               rel.queryHints; | ||||
|         this.maxSize =                  rel.maxSize; | ||||
|         this.offset =                   rel.offset; | ||||
|         this.constraints =              rel.constraints; | ||||
|         this.accessName =               rel.accessName; | ||||
|         this.logicalOperator =          rel.logicalOperator; | ||||
|  | @ -144,39 +146,27 @@ public final class Relation { | |||
|     //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     // parse methods for new file format | ||||
|     //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     public void update(String desc, ResourceProperties props) { | ||||
|     public void update(Object desc, Properties props) { | ||||
|         Application app = ownType.getApplication(); | ||||
| 
 | ||||
|         if ((desc == null) || "".equals(desc.trim())) { | ||||
|             if (propName != null) { | ||||
|                 reftype = PRIMITIVE; | ||||
|                 columnName = propName; | ||||
|             } else { | ||||
|                 reftype = INVALID; | ||||
|                 columnName = propName; | ||||
|             } | ||||
|         } else { | ||||
|             desc = desc.trim(); | ||||
| 
 | ||||
|             int open = desc.indexOf("("); | ||||
|             int close = desc.indexOf(")"); | ||||
| 
 | ||||
|             if ((open > -1) && (close > open)) { | ||||
|                 String ref = desc.substring(0, open).trim(); | ||||
|                 String proto = desc.substring(open + 1, close).trim(); | ||||
| 
 | ||||
|                 if ("collection".equalsIgnoreCase(ref)) { | ||||
|         if (desc instanceof Properties || parseDescriptor(desc, props)) { | ||||
|             // new style foo.collectionOf = Bar mapping | ||||
|             String proto; | ||||
|             if (props.containsKey("collection")) { | ||||
|                 proto = props.getProperty("collection"); | ||||
|                 virtual = !"_children".equalsIgnoreCase(propName); | ||||
|                 reftype = COLLECTION; | ||||
|                 } else if ("mountpoint".equalsIgnoreCase(ref)) { | ||||
|                     virtual = true; | ||||
|             } else if (props.containsKey("mountpoint")) { | ||||
|                 proto = props.getProperty("mountpoint"); | ||||
|                 reftype = COLLECTION; | ||||
|                     prototype = proto; | ||||
|                 } else if ("object".equalsIgnoreCase(ref)) { | ||||
|                     virtual = false; | ||||
|                 virtual = true; | ||||
|                 this.prototype = proto; | ||||
|             } else if (props.containsKey("object")) { | ||||
|                 proto = props.getProperty("object"); | ||||
|                 if (reftype != COMPLEX_REFERENCE) { | ||||
|                     reftype = REFERENCE; | ||||
|                 } | ||||
|                 virtual = false; | ||||
|             } else { | ||||
|                 throw new RuntimeException("Invalid property Mapping: " + desc); | ||||
|             } | ||||
|  | @ -193,24 +183,16 @@ public final class Relation { | |||
|                 otherType.update(); | ||||
|             } | ||||
| 
 | ||||
|             } else { | ||||
|                 virtual = false; | ||||
|                 columnName = desc; | ||||
|                 reftype = PRIMITIVE; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ResourceProperties config = props.getSubProperties(propName + '.'); | ||||
| 
 | ||||
|         readonly = "true".equalsIgnoreCase(config.getProperty("readonly")); | ||||
| 
 | ||||
|         isPrivate = "true".equalsIgnoreCase(config.getProperty("private")); | ||||
|         readonly = "true".equalsIgnoreCase(props.getProperty("readonly")); | ||||
|         isPrivate = "true".equalsIgnoreCase(props.getProperty("private")); | ||||
| 
 | ||||
|         // the following options only apply to object and collection relations | ||||
|         if ((reftype != PRIMITIVE) && (reftype != INVALID)) { | ||||
|             Vector newConstraints = new Vector(); | ||||
| 
 | ||||
|             parseOptions(newConstraints, config); | ||||
|             parseOptions(newConstraints, props); | ||||
| 
 | ||||
|             constraints = new Constraint[newConstraints.size()]; | ||||
|             newConstraints.copyInto(constraints); | ||||
|  | @ -256,32 +238,84 @@ public final class Relation { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected void parseOptions(Vector cnst, Properties config) { | ||||
|         String loading = config.getProperty("loadmode"); | ||||
|     /** | ||||
|      * Converts old style foo = collection(Bar) mapping to new style  | ||||
|      * foo.collection = Bar mappinng and returns true if a non-primitive mapping | ||||
|      * was encountered. | ||||
|      * @param value the value of the top level property mapping | ||||
|      * @param config the sub-map for this property mapping | ||||
|      * @return true if the value describes a valid, non-primitive property mapping | ||||
|      */ | ||||
|     protected boolean parseDescriptor(Object value, Map config) { | ||||
|         String desc = value instanceof String ? (String) value : null; | ||||
| 
 | ||||
|         if ((desc == null) || "".equals(desc.trim())) { | ||||
|             if (propName != null) { | ||||
|                 reftype = PRIMITIVE; | ||||
|                 columnName = propName; | ||||
|             } else { | ||||
|                 reftype = INVALID; | ||||
|                 columnName = propName; | ||||
|             } | ||||
|             return false; | ||||
|         } else { | ||||
|             desc = desc.trim(); | ||||
| 
 | ||||
|             int open = desc.indexOf("("); | ||||
|             int close = desc.indexOf(")"); | ||||
| 
 | ||||
|             if ((open > -1) && (close > open)) { | ||||
|                 String ref = desc.substring(0, open).trim(); | ||||
|                 String proto = desc.substring(open + 1, close).trim(); | ||||
| 
 | ||||
|                 if ("collection".equalsIgnoreCase(ref)) { | ||||
|                     config.put("collection", proto); | ||||
|                 } else if ("mountpoint".equalsIgnoreCase(ref)) { | ||||
|                     config.put("mountpoint", proto); | ||||
|                 } else if ("object".equalsIgnoreCase(ref)) { | ||||
|                     config.put("object", proto); | ||||
|                 } else { | ||||
|                     throw new RuntimeException("Invalid property Mapping: " + desc); | ||||
|                 } | ||||
| 
 | ||||
|                 return true; | ||||
| 
 | ||||
|             } else { | ||||
|                 virtual = false; | ||||
|                 columnName = desc; | ||||
|                 reftype = PRIMITIVE; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     protected void parseOptions(Vector cnst, Properties props) { | ||||
|         String loading = props.getProperty("loadmode"); | ||||
| 
 | ||||
|         aggressiveLoading = (loading != null) && | ||||
|                             "aggressive".equalsIgnoreCase(loading.trim()); | ||||
| 
 | ||||
|         String caching = config.getProperty("cachemode"); | ||||
|         String caching = props.getProperty("cachemode"); | ||||
| 
 | ||||
|         aggressiveCaching = (caching != null) && | ||||
|                             "aggressive".equalsIgnoreCase(caching.trim()); | ||||
| 
 | ||||
|         // get order property | ||||
|         order = config.getProperty("order"); | ||||
|         order = props.getProperty("order"); | ||||
| 
 | ||||
|         if ((order != null) && (order.trim().length() == 0)) { | ||||
|             order = null; | ||||
|         } | ||||
| 
 | ||||
|         // get the criteria(s) for updating this collection | ||||
|         updateCriteria = config.getProperty("updatecriteria"); | ||||
|         updateCriteria = props.getProperty("updatecriteria"); | ||||
| 
 | ||||
|         // get the autosorting flag | ||||
|         autoSorted = "auto".equalsIgnoreCase(config.getProperty("sortmode")); | ||||
|         autoSorted = "auto".equalsIgnoreCase(props.getProperty("sortmode")); | ||||
| 
 | ||||
|         // get additional filter property | ||||
|         filter = config.getProperty("filter"); | ||||
|         filter = props.getProperty("filter"); | ||||
| 
 | ||||
|         if (filter != null) { | ||||
|             if (filter.trim().length() == 0) { | ||||
|  | @ -304,7 +338,7 @@ public final class Relation { | |||
|         } | ||||
| 
 | ||||
|         // get additional tables | ||||
|         additionalTables = config.getProperty("filter.additionalTables"); | ||||
|         additionalTables = props.getProperty("filter.additionalTables"); | ||||
| 
 | ||||
|         if (additionalTables != null) { | ||||
|             if (additionalTables.trim().length() == 0) { | ||||
|  | @ -334,36 +368,31 @@ public final class Relation { | |||
|         } | ||||
| 
 | ||||
|         // get query hints | ||||
|         queryHints = config.getProperty("hints"); | ||||
|         queryHints = props.getProperty("hints"); | ||||
| 
 | ||||
|         // get max size of collection | ||||
|         String max = config.getProperty("maxSize"); | ||||
| 
 | ||||
|         if (max != null) { | ||||
|             try { | ||||
|                 maxSize = Integer.parseInt(max); | ||||
|             } catch (NumberFormatException nfe) { | ||||
|                 maxSize = 0; | ||||
|             } | ||||
|         } else { | ||||
|             maxSize = 0; | ||||
|         maxSize = getIntegerProperty("maxSize", props, 0); | ||||
|         if (maxSize == 0) { | ||||
|             // use limit as alias for maxSize | ||||
|             maxSize = getIntegerProperty("limit", props, 0); | ||||
|         } | ||||
|         offset = getIntegerProperty("offset", props, 0); | ||||
| 
 | ||||
|         // get group by property | ||||
|         groupby = config.getProperty("group"); | ||||
|         groupby = props.getProperty("group"); | ||||
| 
 | ||||
|         if ((groupby != null) && (groupby.trim().length() == 0)) { | ||||
|             groupby = null; | ||||
|         } | ||||
| 
 | ||||
|         if (groupby != null) { | ||||
|             groupbyOrder = config.getProperty("group.order"); | ||||
|             groupbyOrder = props.getProperty("group.order"); | ||||
| 
 | ||||
|             if ((groupbyOrder != null) && (groupbyOrder.trim().length() == 0)) { | ||||
|                 groupbyOrder = null; | ||||
|             } | ||||
| 
 | ||||
|             groupbyPrototype = config.getProperty("group.prototype"); | ||||
|             groupbyPrototype = props.getProperty("group.prototype"); | ||||
| 
 | ||||
|             if ((groupbyPrototype != null) && (groupbyPrototype.trim().length() == 0)) { | ||||
|                 groupbyPrototype = null; | ||||
|  | @ -374,11 +403,11 @@ public final class Relation { | |||
|         } | ||||
| 
 | ||||
|         // check if subnode condition should be applied for property relations | ||||
|         accessName = config.getProperty("accessname"); | ||||
|         accessName = props.getProperty("accessname"); | ||||
| 
 | ||||
|         // parse contstraints | ||||
|         String local = config.getProperty("local"); | ||||
|         String foreign = config.getProperty("foreign"); | ||||
|         String local = props.getProperty("local"); | ||||
|         String foreign = props.getProperty("foreign"); | ||||
| 
 | ||||
|         if ((local != null) && (foreign != null)) { | ||||
|             cnst.addElement(new Constraint(local, foreign, false)); | ||||
|  | @ -387,8 +416,8 @@ public final class Relation { | |||
| 
 | ||||
|         // parse additional contstraints from *.1 to *.9 | ||||
|         for (int i=1; i<10; i++) { | ||||
|             local = config.getProperty("local."+i); | ||||
|             foreign = config.getProperty("foreign."+i); | ||||
|             local = props.getProperty("local."+i); | ||||
|             foreign = props.getProperty("foreign."+i); | ||||
| 
 | ||||
|             if ((local != null) && (foreign != null)) { | ||||
|                 cnst.addElement(new Constraint(local, foreign, false)); | ||||
|  | @ -397,7 +426,7 @@ public final class Relation { | |||
| 
 | ||||
|         // parse constraints logic | ||||
|         if (cnst.size() > 1) { | ||||
|             String logic = config.getProperty("logicalOperator"); | ||||
|             String logic = props.getProperty("logicalOperator"); | ||||
|             if ("and".equalsIgnoreCase(logic)) { | ||||
|                 logicalOperator = AND; | ||||
|             } else if ("or".equalsIgnoreCase(logic)) { | ||||
|  | @ -413,13 +442,24 @@ public final class Relation { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private int getIntegerProperty(String name, Properties props, int defaultValue) { | ||||
|         Object value = props.get(name); | ||||
| 
 | ||||
|         if (value instanceof Number) { | ||||
|             return ((Number) value).intValue(); | ||||
|         } else if (value instanceof String) { | ||||
|             return Integer.parseInt((String) value); | ||||
|         } | ||||
|         return defaultValue; | ||||
|     } | ||||
| 
 | ||||
|     /////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 
 | ||||
|     /** | ||||
|      * Get the configuration properties for this relation. | ||||
|      */ | ||||
|     public ResourceProperties getConfig() { | ||||
|         return ownType.getProperties().getSubProperties(propName + '.'); | ||||
|     public Map getConfig() { | ||||
|         return ownType.getSubProperties(propName + '.'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -875,6 +915,13 @@ public final class Relation { | |||
|             q.append(" ORDER BY ").append(order); | ||||
|         } | ||||
| 
 | ||||
|         if (maxSize > 0 && !ownType.isOracle()) { | ||||
|             q.append(" LIMIT ").append(maxSize); | ||||
|             if (offset > 0) { | ||||
|                 q.append(" OFFSET ").append(offset); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return q.toString(); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ package helma.scripting.rhino; | |||
| 
 | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.Properties; | ||||
| 
 | ||||
| import helma.objectmodel.INode; | ||||
| import helma.objectmodel.db.DbMapping; | ||||
|  | @ -58,6 +59,7 @@ public class HopObjectCtor extends FunctionObject { | |||
|         this.protoProperty = prototype; | ||||
|         addAsConstructor(core.global, prototype); | ||||
|         defineProperty("getById", new GetById(core.global), attr); | ||||
|         defineProperty("getCollection", new HopCollection(core.global), attr); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -180,4 +182,44 @@ public class HopObjectCtor extends FunctionObject { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     class HopCollection extends BaseFunction { | ||||
| 
 | ||||
|         public HopCollection(Scriptable scope) { | ||||
|             ScriptRuntime.setFunctionProtoAndParent(this, scope); | ||||
|         } | ||||
| 
 | ||||
|         public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { | ||||
|             if (args.length != 1) { | ||||
|                 throw new IllegalArgumentException("Wrong number of arguments in definePrototype()"); | ||||
|             } | ||||
|             if (!(args[0] instanceof Scriptable)) { | ||||
|                 throw new IllegalArgumentException("Second argument to HopObject.definePrototype() must be Object"); | ||||
|             } | ||||
| 
 | ||||
|             Scriptable desc = (Scriptable) args[0]; | ||||
|             Properties childmapping = core.scriptableToProperties(desc); | ||||
|             if (!childmapping.containsKey("collection")) { | ||||
|                 // if contained type isn't defined explicitly limit collection to our own type | ||||
|                 childmapping.put("collection", HopObjectCtor.this.getFunctionName()); | ||||
|             } | ||||
| 
 | ||||
|             Node node = new Node("HopQuery", null, core.app.getWrappedNodeManager()); | ||||
|             Properties props = new Properties(); | ||||
|             props.put("_children", childmapping); | ||||
|             DbMapping dbmap = new DbMapping(core.app, null, props); | ||||
|             dbmap.update(); | ||||
|             node.setDbMapping(dbmap); | ||||
|             node.setState(Node.VIRTUAL); | ||||
|             return new HopObject("HopQuery", core, node, core.hopObjectProto); | ||||
|         } | ||||
| 
 | ||||
|         public int getArity() { | ||||
|             return 1; | ||||
|         } | ||||
| 
 | ||||
|         public int getLength() { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -23,10 +23,7 @@ import helma.framework.repository.Resource; | |||
| import helma.objectmodel.*; | ||||
| import helma.objectmodel.db.DbMapping; | ||||
| import helma.scripting.*; | ||||
| import helma.util.CacheMap; | ||||
| import helma.util.SystemMap; | ||||
| import helma.util.WrappedMap; | ||||
| import helma.util.WeakCacheMap; | ||||
| import helma.util.*; | ||||
| import org.mozilla.javascript.*; | ||||
| import org.mozilla.javascript.tools.debugger.ScopeProvider; | ||||
| 
 | ||||
|  | @ -216,7 +213,7 @@ public final class RhinoCore implements ScopeProvider { | |||
|      * | ||||
|      *  @param prototype the prototype to be created | ||||
|      */ | ||||
|     private synchronized void initPrototype(Prototype prototype) { | ||||
|     protected synchronized TypeInfo initPrototype(Prototype prototype) { | ||||
| 
 | ||||
|         String name = prototype.getName(); | ||||
|         String lowerCaseName = prototype.getLowerCaseName(); | ||||
|  | @ -236,7 +233,7 @@ public final class RhinoCore implements ScopeProvider { | |||
|             } else { | ||||
|                 op = new HopObject(name, this); | ||||
|             } | ||||
|             registerPrototype(prototype, op); | ||||
|             type = registerPrototype(prototype, op); | ||||
|         } | ||||
| 
 | ||||
|         // Register a constructor for all types except global. | ||||
|  | @ -250,6 +247,8 @@ public final class RhinoCore implements ScopeProvider { | |||
|                 app.logError("Error adding ctor for " + name,  x); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -291,7 +290,7 @@ public final class RhinoCore implements ScopeProvider { | |||
|      *  @param prototype the prototype spec | ||||
|      *  @param type the prototype object info | ||||
|      */ | ||||
|     private void setParentPrototype(Prototype prototype, TypeInfo type) { | ||||
|     protected void setParentPrototype(Prototype prototype, TypeInfo type) { | ||||
|         String name = prototype.getName(); | ||||
|         String lowerCaseName = prototype.getLowerCaseName(); | ||||
| 
 | ||||
|  | @ -748,6 +747,26 @@ public final class RhinoCore implements ScopeProvider { | |||
|         return href; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Properties scriptableToProperties(Scriptable obj) { | ||||
|         Object[] ids = obj.getIds(); | ||||
|         Properties props = new ResourceProperties(app, null, null, true); | ||||
|         for (int i = 0; i < ids.length; i++) { | ||||
|             // we ignore non-string keys | ||||
|             if (ids[i] instanceof String) { | ||||
|                 String key = (String) ids[i]; | ||||
|                 Object value = obj.get(key, obj); | ||||
|                 if (value == Undefined.instance || value == Scriptable.NOT_FOUND) { | ||||
|                     value = null; | ||||
|                 } else if (value instanceof Scriptable) { | ||||
|                     value = scriptableToProperties((Scriptable) value); | ||||
|                 } | ||||
|                 props.put(key, value); | ||||
|             } | ||||
|         } | ||||
|         return props; | ||||
|     }     | ||||
| 
 | ||||
|     /** | ||||
|      * Get the RhinoCore instance associated with the current thread, or null | ||||
|      * @return the RhinoCore instance associated with the current thread | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue