Return a transient HopObject instead of a ListViewWrapper in HopObject.getOrderedView(). Do import helma.objectmodel.db.Node in HopObject.

This commit is contained in:
hns 2008-10-17 16:04:28 +00:00
parent 0e7c4354c9
commit 99c9b3a867
4 changed files with 22 additions and 357 deletions

View file

@ -381,7 +381,7 @@ public class OrderedSubnodeList extends SubnodeList {
return 0;
}
public List getOrderedView (String order) {
public SubnodeList getOrderedView (String order) {
if (origin != null) {
return origin.getOrderedView(order);
} else {

View file

@ -104,7 +104,7 @@ public class SubnodeList extends ArrayList {
}
}
public List getOrderedView (String order) {
public SubnodeList getOrderedView (String order) {
String key = order.trim().toLowerCase();
// long start = System.currentTimeMillis();
if (views == null) {

View file

@ -20,6 +20,7 @@ import helma.framework.core.*;
import helma.framework.repository.Resource;
import helma.objectmodel.*;
import helma.objectmodel.db.*;
import helma.objectmodel.db.Node;
import org.mozilla.javascript.*;
import java.lang.reflect.Method;
@ -170,13 +171,13 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
*/
private void checkNode() {
if (node != null && node.getState() == INode.INVALID) {
if (node instanceof helma.objectmodel.db.Node) {
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
if (node instanceof Node) {
NodeHandle handle = ((Node) node).getHandle();
node = handle.getNode(core.app.getWrappedNodeManager());
if (node == null) {
// we probably have a deleted node. Replace with empty transient node
// to avoid throwing an exception.
node = new helma.objectmodel.TransientNode();
node = new TransientNode();
// throw new RuntimeException("Tried to access invalid/removed node " + handle + ".");
}
}
@ -455,14 +456,14 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
}
private void prefetchChildren(int start, int length) {
if (!(node instanceof helma.objectmodel.db.Node)) {
if (!(node instanceof Node)) {
return;
}
checkNode();
try {
((helma.objectmodel.db.Node) node).prefetchChildren(start, length);
((Node) node).prefetchChildren(start, length);
} catch (Exception x) {
core.app.logError("Error in HopObject.prefetchChildren: " + x, x);
}
@ -638,8 +639,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
checkNode();
if (node instanceof helma.objectmodel.db.Node) {
((helma.objectmodel.db.Node) node).persist();
if (node instanceof Node) {
((Node) node).persist();
return node.getID();
}
return null;
@ -649,19 +650,19 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* Invalidate the node itself or a subnode
*/
public boolean jsFunction_invalidate(Object childId) {
if (childId != null && node instanceof helma.objectmodel.db.Node) {
if (childId != null && node instanceof Node) {
if (childId == Undefined.instance) {
if (node.getState() == INode.INVALID) {
return true;
}
((helma.objectmodel.db.Node) node).invalidate();
((Node) node).invalidate();
} else {
checkNode();
((helma.objectmodel.db.Node) node).invalidateNode(childId.toString());
((Node) node).invalidateNode(childId.toString());
}
}
@ -675,7 +676,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* @return true if the the wrapped Node has a valid database id.
*/
public boolean jsFunction_isPersistent() {
if (!(node instanceof helma.objectmodel.db.Node)) {
if (!(node instanceof Node)) {
return false;
}
checkNode();
@ -690,7 +691,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* @return true if the the wrapped Node is not stored in a database.
*/
public boolean jsFunction_isTransient() {
if (!(node instanceof helma.objectmodel.db.Node)) {
if (!(node instanceof Node)) {
return true;
}
checkNode();
@ -1096,10 +1097,10 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* do have a higher id than the last record loaded by this collection
*/
public int jsFunction_update() {
if (!(node instanceof helma.objectmodel.db.Node))
if (!(node instanceof Node))
throw new RuntimeException ("update only callabel on persistent HopObjects");
checkNode();
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
Node n = (Node) node;
return n.updateSubnodes();
}
@ -1111,18 +1112,19 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
* @return ListViewWrapper holding the information of the ordered view
*/
public Object jsFunction_getOrderedView(String expr) {
if (!(node instanceof helma.objectmodel.db.Node)) {
if (!(node instanceof Node)) {
throw new RuntimeException (
"getOrderedView only callable on persistent HopObjects");
}
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
Node n = (Node) node;
n.loadNodes();
SubnodeList subnodes = n.getSubnodeList();
if (subnodes == null) {
throw new RuntimeException (
"getOrderedView only callable on already existing subnode-collections");
}
return new ListViewWrapper (subnodes.getOrderedView(expr),
core, core.app.getWrappedNodeManager(), this);
Node subnode = new Node("OrderedView", "HopObject", core.app.getWrappedNodeManager());
subnode.setSubnodes(subnodes.getOrderedView(expr));
return new HopObject("HopObject", core, subnode, core.getPrototype("HopObject"));
}
}

View file

@ -1,337 +0,0 @@
/*
* Helma License Notice
*
* The contents of this file are subject to the Helma License
* Version 2.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://adele.helma.org/download/helma/license.txt
*
* Copyright 1998-2003 Helma Software. All Rights Reserved.
*
* $RCSfile$
* $Author$
* $Revision$
* $Date$
*/
package helma.scripting.rhino;
import helma.objectmodel.INode;
import helma.objectmodel.db.Key;
import helma.objectmodel.db.NodeHandle;
import helma.objectmodel.db.OrderedSubnodeList;
import helma.objectmodel.db.WrappedNodeManager;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.Wrapper;
import org.mozilla.javascript.ScriptRuntime;
public class ListViewWrapper extends ScriptableObject implements Wrapper, Scriptable {
final List list;
final RhinoCore core;
final WrappedNodeManager wnm;
final HopObject hObj;
INode node;
static ListViewWrapper listViewProto;
/**
* Private constructor used to create the object prototype.
*/
private ListViewWrapper() {
list = null;
core = null;
wnm = null;
node = null;
hObj = null;
}
/**
* Create a JS wrapper around a subnode list.
* @param list
* @param core
* @param wnm
* @param hObj
*/
ListViewWrapper (List list, RhinoCore core, WrappedNodeManager wnm, HopObject hObj) {
if (list == null) {
throw new IllegalArgumentException ("ListWrapper unable to wrap null list.");
}
this.core = core;
this.list = list;
this.wnm = wnm;
this.hObj = hObj;
this.node = hObj.node;
if (listViewProto == null) {
listViewProto = new ListViewWrapper();
listViewProto.init();
}
setPrototype(listViewProto);
}
/**
* Init JS functions from methods.
*/
void init() {
int attributes = DONTENUM | PERMANENT;
Method[] methods = getClass().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], this);
this.defineProperty(methodName, func, attributes);
}
}
}
public Object unwrap() {
return list;
}
public Object jsFunction_get(Object idxObj) {
if (idxObj instanceof Number)
return jsFunction_get(((Number) idxObj).intValue());
else // fallback to this View's HopObject's get-function
return hObj.jsFunction_get(idxObj);
}
public Object jsFunction_get(int idx) {
// return null if given index is out of bounds
if (list.size() <= idx)
return null;
Object obj = list.get(idx);
// return null if indexed object is null
if (obj == null)
return null;
// return HopObject in case of a NodeHandle
if (obj instanceof NodeHandle) {
return Context.toObject(((NodeHandle) obj).getNode(wnm), core.global);
} else if (!(obj instanceof Scriptable)) {
// do NOT wrap primitives - otherwise they'll be wrapped as Objects,
// which makes them unusable for many purposes (e.g. ==)
if (obj instanceof String ||
obj instanceof Number ||
obj instanceof Boolean) {
return obj;
}
return Context.toObject(obj, core.global);
}
return obj;
}
public Object jsFunction_getById(Object id) {
return hObj.jsFunction_getById(id);
}
/**
* Prefetch child objects from (relational) database.
*/
public void jsFunction_prefetchChildren(Object startArg, Object lengthArg)
throws Exception {
// 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) {
if (!(node instanceof helma.objectmodel.db.Node))
return;
checkNode();
start = Math.max(start, 0);
length = Math.min(list.size() - start, length);
if (length < 1)
return;
Key[] keys = new Key[length];
for (int i = start; i < start+length; i++) {
keys[i - start] = ((NodeHandle) list.get(i)).getKey();
}
try {
((helma.objectmodel.db.Node) node).prefetchChildren(keys);
} catch (Exception x) {
System.err.println("Error in HopObject.prefetchChildren(): " + x);
}
}
public int jsFunction_size() {
if (list==null)
return 0;
return list.size();
}
public int jsFunction_count() {
return jsFunction_size();
}
public void jsFunction_add(Object child) {
if (this.hObj==null)
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
hObj.jsFunction_add(child);
}
/**
* Return the full list of child objects in a JavaScript Array.
* This is called by jsFunction_list() if called with no arguments.
*
* @return A JavaScript Array containing all child objects
*/
private Scriptable list() {
checkNode();
ArrayList a = new ArrayList();
for (Iterator i = list.iterator(); i.hasNext(); ) {
NodeHandle nh = (NodeHandle) i.next();
if (nh!=null)
a.add(Context.toObject(nh.getNode(wnm), core.global));
}
return Context.getCurrentContext().newArray(core.global, a.toArray());
}
/**
* Return a JS array of child objects with the given start and length.
*
* @return A JavaScript Array containing the specified child objects
*/
public Scriptable jsFunction_list(Object startArg, Object lengthArg) {
if (startArg == Undefined.instance && lengthArg == Undefined.instance) {
return list();
}
int start = (int) ScriptRuntime.toNumber(startArg);
int length = (int) ScriptRuntime.toNumber(lengthArg);
if (start < 0 || length < 0) {
throw new EvaluatorException("Arguments must not be negative in HopObject.list(start, length)");
}
checkNode();
start = Math.max(start, 0);
length = Math.min(list.size() - start, length);
prefetchChildren(start, length);
ArrayList a = new ArrayList();
for (int i=start; i<start+length; i++) {
NodeHandle nh = (NodeHandle) list.get(i);
if (nh != null)
a.add(Context.toObject(nh.getNode(wnm), core.global));
}
return Context.getCurrentContext().newArray(core.global, a.toArray());
}
/**
* Remove this object from the database.
*/
public boolean jsFunction_remove(Object arg) {
if (this.hObj==null)
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
return hObj.jsFunction_remove(arg);
}
/**
* Remove a child node from this node's collection without deleting
* it from the database.
*/
public boolean jsFunction_removeChild(Object child) {
if (this.hObj==null)
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
return hObj.jsFunction_removeChild(child);
}
/**
* Invalidate the node itself or a subnode
*/
public boolean jsFunction_invalidate(Object childId) {
if (this.hObj==null)
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
return hObj.jsFunction_invalidate(childId);
}
/**
* Check if node is contained in subnodes
*/
public int jsFunction_contains(Object obj) {
if (obj instanceof HopObject) {
INode n = ((HopObject) obj).node;
if (n instanceof helma.objectmodel.db.Node)
return list.indexOf(((helma.objectmodel.db.Node) n).getHandle());
}
return -1;
}
/**
* This method represents the Java-Script-exposed function for updating Subnode-Collections.
* The following conditions must be met to make a subnodecollection updateable.
* .) the collection must be specified with collection.updateable=true
* .) the id's of this collection must be in ascending order, meaning, that new records
* do have a higher id than the last record loaded by this collection
*/
public int jsFunction_update() {
if (!(node instanceof helma.objectmodel.db.Node))
throw new RuntimeException ("updateSubnodes only callabel on persistent HopObjects");
checkNode();
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
return n.updateSubnodes();
}
/**
* Retrieve a view having a different order from this Node's subnodelist.
* The underlying OrderedSubnodeList will keep those views and updates them
* if the original collection has been updated.
* @param expr the order (like sql-order using the properties instead)
* @return ListViewWrapper holding the information of the ordered view
*/
public Object jsFunction_getOrderedView(String expr) {
if (!(list instanceof OrderedSubnodeList))
throw new RuntimeException ("getOrderedView only callable on persistent HopObjects");
checkNode();
OrderedSubnodeList osl = (OrderedSubnodeList) list;
return new ListViewWrapper (osl.getOrderedView(expr), core, wnm, hObj);
}
public String toString() {
if (list==null)
return "[ListWrapper{}]";
else
return "[ListWrapper"+ list.toString() + "]";
}
/**
* Check if the node has been invalidated. If so, it has to be re-fetched
* from the db via the app's node manager.
*/
private final void checkNode() {
if (node != null && node.getState() == INode.INVALID) {
if (node instanceof helma.objectmodel.db.Node) {
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
node = handle.getNode(core.app.getWrappedNodeManager());
}
}
}
public String getClassName() {
return "[ListWrapper]";
}
}