Author: hannes
Date: 2009-04-07 15:03:55 +0200 (Tue, 07 Apr 2009)
New Revision: 9581
Modified:
helma/helma/branches/lazy_collections/src/helma/objectmodel/db/NodeHandle.java
helma/helma/branches/lazy_collections/src/helma/objectmodel/db/SubnodeList.java
helma/helma/branches/lazy_collections/src/helma/scripting/rhino/HopObject.java
helma/helma/branches/lazy_collections/src/helma/scripting/rhino/RhinoCore.java
helma/helma/branches/lazy_collections/src/helma/scripting/rhino/SerializationProxy.java
Log:
- Finish implementation of HopObject wrappers for lazy-fetched nodes.
- Fix HopObject.list() performance by not fetching any nodes (when called
without arguments), or prefetching the nodes (when called with start, length
arguments).
- Fix == operator for HopObjects to compare NodeHandles rather than Nodes.
- Some code and documentation improvements in NodeHandle
Details at http://dev.helma.org/trac/helma/changeset/9581
Modified: helma/helma/branches/lazy_collections/src/helma/objectmodel/db/NodeHandle.java
===================================================================
--- helma/helma/branches/lazy_collections/src/helma/objectmodel/db/NodeHandle.java 2009-04-06 15:41:06 UTC (rev 9580)
+++ helma/helma/branches/lazy_collections/src/helma/objectmodel/db/NodeHandle.java 2009-04-07 13:03:55 UTC (rev 9581)
@@ -29,6 +29,15 @@
* While a direct reference may point to a node that has been evicted from the cache
* and reinstanciated since being set, NodeHandle will always return an up-to-date
* instance of its node.
+ *
+ * Helma tries to ensure the following rules on NodeHandles:
+ * <ol>
+ * <li> For transient nodes there exists only one NodeHandle.</li>
+ * <li> If a transient node becomes persistent its node handle is notified and
+ * converted into a persistent NodeHandle.</li>
+ * </ol>
+ * These two properties guarantee that NodeHandle comparisons are easy and usually correct.
+ *
*/
public final class NodeHandle implements INodeState, Serializable {
static final long serialVersionUID = 3067763116576910931L;
@@ -40,9 +49,12 @@
private Key key;
/**
- * Builds a handle for a node
+ * Builds a handle for a node. This constructor is package private in order to make
+ * sure only one NodeHandle exists per transient node. Use {@link Node#getHandle()}
+ * to get a Node's handle.
+ * @param node the node
*/
- public NodeHandle(Node node) {
+ NodeHandle(Node node) {
int state = node.getState();
if (state == TRANSIENT) {
@@ -58,6 +70,7 @@
* Builds a handle given a node's retrieval information. At the time this is called,
* the node is ususally not yet created. It will be fetched on demand when accessed by
* application code.
+ * @param key the key
*/
public NodeHandle(Key key) {
this.node = null;
@@ -84,12 +97,9 @@
/**
* Get the key for the node described by this handle.
- * This may only be called on persistent Nodes.
+ * This will return null for transient Nodes.
*/
public Key getKey() {
- if (key == null) {
- throw new RuntimeException("getKey called on transient Node");
- }
return key;
}
@@ -120,11 +130,12 @@
* @return ...
*/
public boolean equals(Object other) {
- try {
- return getObject().equals(((NodeHandle) other).getObject());
- } catch (Exception x) {
- return false;
+ if (other instanceof NodeHandle) {
+ Object obj1 = getObject();
+ Object obj2 = ((NodeHandle) other).getObject();
+ return obj1 == obj2 || obj1.equals(obj2);
}
+ return false;
}
/**
Modified: helma/helma/branches/lazy_collections/src/helma/objectmodel/db/SubnodeList.java
===================================================================
--- helma/helma/branches/lazy_collections/src/helma/objectmodel/db/SubnodeList.java 2009-04-06 15:41:06 UTC (rev 9580)
+++ helma/helma/branches/lazy_collections/src/helma/objectmodel/db/SubnodeList.java 2009-04-07 13:03:55 UTC (rev 9581)
@@ -74,6 +74,7 @@
if (handle != null) {
retval = handle.getNode(node.nmgr);
+ // Legacy alarm!
if ((retval != null) && (retval.parentHandle == null) &&
!node.nmgr.isRootNode(retval)) {
retval.setParent(node);
@@ -108,6 +109,10 @@
return list.remove(obj);
}
+ public Object[] toArray() {
+ return list.toArray();
+ }
+
/**
* Return the size of the list.
* @return the list size
Modified: helma/helma/branches/lazy_collections/src/helma/scripting/rhino/HopObject.java
===================================================================
--- helma/helma/branches/lazy_collections/src/helma/scripting/rhino/HopObject.java 2009-04-06 15:41:06 UTC (rev 9580)
+++ helma/helma/branches/lazy_collections/src/helma/scripting/rhino/HopObject.java 2009-04-07 13:03:55 UTC (rev 9581)
@@ -468,18 +468,17 @@
* @return A JavaScript Array containing all child objects
*/
private Scriptable list() {
- INode node = getNode();
-
- Enumeration e = node.getSubnodes();
- ArrayList a = new ArrayList();
-
- while ((e != null) && e.hasMoreElements()) {
- Object obj = e.nextElement();
- if (obj != null)
- a.add(Context.toObject(obj, core.global));
+ Node node = (Node) getNode();
+ node.loadNodes();
+ SubnodeList list = node.getSubnodeList();
+ if (list == null) {
+ return Context.getCurrentContext().newArray(core.global, 0);
}
-
- return Context.getCurrentContext().newArray(core.global, a.toArray());
+ Object[] array = list.toArray();
+ for (int i = 0; i < array.length; i++) {
+ array[i] = core.getNodeWrapper((NodeHandle) array[i]);
+ }
+ return Context.getCurrentContext().newArray(core.global, array);
}
/**
@@ -499,18 +498,19 @@
throw new EvaluatorException("Arguments must not be negative in HopObject.list(start, length)");
}
- INode node = getNode();
+ Node node = (Node) getNode();
prefetchChildren(start, length);
- ArrayList a = new ArrayList();
+ SubnodeList list = node.getSubnodeList();
+ Object[] array = new Object[length];
- for (int i=start; i<start+length; i++) {
- INode n = node.getSubnodeAt(i);
- if (n != null) {
- a.add(Context.toObject(n, core.global));
+ for (int i = 0; i < length; i++) {
+ Object obj = list.get(start + i);
+ if (obj != null) {
+ array[i] = Context.toObject(obj, core.global);
}
}
- return Context.getCurrentContext().newArray(core.global, a.toArray());
+ return Context.getCurrentContext().newArray(core.global, array);
}
/**
@@ -1016,6 +1016,24 @@
}
/**
+ * Custom <tt>==</tt> operator.
+ * Must return {@link org.mozilla.javascript.Scriptable#NOT_FOUND} if this object does not
+ * have custom equality operator for the given value,
+ * <tt>Boolean.TRUE</tt> if this object is equivalent to <tt>value</tt>,
+ * <tt>Boolean.FALSE</tt> if this object is not equivalent to
+ * <tt>value</tt>.
+ */
+ protected Object equivalentValues(Object value) {
+ if (value == this) {
+ return Boolean.TRUE;
+ }
+ if (value instanceof HopObject && proxy != null) {
+ return proxy.equivalentValues(((HopObject) value).proxy);
+ }
+ return Scriptable.NOT_FOUND;
+ }
+
+ /**
* Return a string representation of this HopObject.
* @return a string representing this HopObject
*/
@@ -1104,6 +1122,9 @@
NodeProxy(INode node) {
this.node = node;
+ if (node instanceof Node) {
+ handle = ((Node) node).getHandle();
+ }
}
NodeProxy(NodeHandle handle) {
@@ -1133,5 +1154,15 @@
}
return node;
}
+
+ public Boolean equivalentValues(NodeProxy other) {
+ if (handle == null) {
+ return other.node == this.node ?
+ Boolean.TRUE : Boolean.FALSE;
+ } else {
+ return handle.equals(other.handle) ?
+ Boolean.TRUE : Boolean.FALSE;
+ }
+ }
}
}
Modified: helma/helma/branches/lazy_collections/src/helma/scripting/rhino/RhinoCore.java
===================================================================
--- helma/helma/branches/lazy_collections/src/helma/scripting/rhino/RhinoCore.java 2009-04-06 15:41:06 UTC (rev 9580)
+++ helma/helma/branches/lazy_collections/src/helma/scripting/rhino/RhinoCore.java 2009-04-07 13:03:55 UTC (rev 9581)
@@ -22,9 +22,26 @@
import helma.framework.repository.Resource;
import helma.objectmodel.*;
import helma.objectmodel.db.DbMapping;
+import helma.objectmodel.db.NodeHandle;
import helma.scripting.*;
import helma.util.*;
-import org.mozilla.javascript.*;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ContextAction;
+import org.mozilla.javascript.ContextFactory;
+import org.mozilla.javascript.BaseFunction;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.JavaScriptException;
+import org.mozilla.javascript.LazilyLoadedCtor;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.NativeJavaObject;
+import org.mozilla.javascript.NativeObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.ScriptRuntime;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.WrapFactory;
+import org.mozilla.javascript.Wrapper;
import org.mozilla.javascript.tools.debugger.ScopeProvider;
import java.io.*;
@@ -637,15 +654,15 @@
/**
* Get a script wrapper for an instance of helma.objectmodel.INode
*/
- public Scriptable getNodeWrapper(INode n) {
- if (n == null) {
+ public Scriptable getNodeWrapper(INode node) {
+ if (node == null) {
return null;
}
- HopObject hobj = (HopObject) wrappercache.get(n);
+ HopObject hobj = (HopObject) wrappercache.get(node);
if (hobj == null) {
- String protoname = n.getPrototype();
+ String protoname = node.getPrototype();
Scriptable op = getValidPrototype(protoname);
// no prototype found for this node
@@ -654,7 +671,7 @@
// deleted, but the storage layer was able to set a
// DbMapping matching the relational table the object
// was fetched from.
- DbMapping dbmap = n.getDbMapping();
+ DbMapping dbmap = node.getDbMapping();
if (dbmap != null && (protoname = dbmap.getTypeName()) != null) {
op = getValidPrototype(protoname);
}
@@ -666,13 +683,42 @@
}
}
- hobj = new HopObject(protoname, this, n, op);
- wrappercache.put(n, hobj);
+ hobj = new HopObject(protoname, this, node, op);
+ wrappercache.put(node, hobj);
}
return hobj;
}
+ /**
+ * Get a node wrapper for a node that may not have been fetched yet
+ * @param handle a node handle
+ * @return a wrapper for the node
+ */
+ public Scriptable getNodeWrapper(NodeHandle handle) {
+ Scriptable hobj = (HopObject) wrappercache.get(handle);
+ if (hobj != null) {
+ return hobj;
+ } else if (handle.hasNode()) {
+ hobj = getNodeWrapper(handle.getNode(app.getWrappedNodeManager()));
+ }
+
+ if (hobj == null) {
+ String protoName = handle.getKey().getStorageName();
+ Scriptable op = getValidPrototype(protoName);
+
+ // no prototype found for this node
+ if (op == null) {
+ protoName = "HopObject";
+ op = getValidPrototype("HopObject");
+ }
+ hobj = new HopObject(protoName, this, handle, op);
+ }
+ wrappercache.put(handle, hobj);
+ return hobj;
+ }
+
+
protected String postProcessHref(Object obj, String protoName, String href)
throws UnsupportedEncodingException, IOException {
// check if the app.properties specify a href-function to post-process the
@@ -1057,6 +1103,9 @@
if (obj instanceof INode) {
return getNodeWrapper((INode) obj);
}
+ if (obj instanceof NodeHandle) {
+ return getNodeWrapper((NodeHandle) obj);
+ }
// Masquerade SystemMap and WrappedMap as native JavaScript objects
if (obj instanceof SystemMap || obj instanceof WrappedMap) {
Modified: helma/helma/branches/lazy_collections/src/helma/scripting/rhino/SerializationProxy.java
===================================================================
--- helma/helma/branches/lazy_collections/src/helma/scripting/rhino/SerializationProxy.java 2009-04-06 15:41:06 UTC (rev 9580)
+++ helma/helma/branches/lazy_collections/src/helma/scripting/rhino/SerializationProxy.java 2009-04-07 13:03:55 UTC (rev 9581)
@@ -85,7 +85,7 @@
ref = obj.getClassName();
} else {
if (n instanceof Node) {
- ref = new NodeHandle((Node) n);
+ ref = ((Node) n).getHandle();
} else {
ref = n;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.