Return a transient HopObject instead of a ListViewWrapper in HopObject.getOrderedView(). Do import helma.objectmodel.db.Node in HopObject.
This commit is contained in:
parent
0e7c4354c9
commit
99c9b3a867
4 changed files with 22 additions and 357 deletions
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]";
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue