* Clean up HopObject wrapper, move constructor code into separate HopObjectCtor class
* Implement HopObject compilation trigger on HopObject constructor property access * Fix race condition in RhinoCore.updatePrototypes() that could result in failed requests at application startup time; tighten up synchronization. * Fix ListViewWrapper to perform static JS function setup rather than setting up functions for each wrapper. * Implement getOrderedView() in SubnodeList (pulled out of OrderedSubnodeList). * Cleaned up and simplified OrderedSubnodeList. * Change ordering for null properties: add at the end of the list instead of the beginning. * Cache nodes fetched in NodeManager.updateSubnodeList()
This commit is contained in:
parent
91a92b6072
commit
80e0d4e012
10 changed files with 494 additions and 412 deletions
|
@ -1244,7 +1244,7 @@ public final class Node implements INode, Serializable {
|
||||||
loadNodes();
|
loadNodes();
|
||||||
|
|
||||||
if (subnodes == null) {
|
if (subnodes == null) {
|
||||||
subnodes = new SubnodeList();
|
subnodes = new SubnodeList(nmgr, dbmap.getSubnodeRelation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create || subnodes.contains(new NodeHandle(new SyntheticKey(getKey(), sid)))) {
|
if (create || subnodes.contains(new NodeHandle(new SyntheticKey(getKey(), sid)))) {
|
||||||
|
@ -1582,11 +1582,11 @@ public final class Node implements INode, Serializable {
|
||||||
public SubnodeList createSubnodeList() {
|
public SubnodeList createSubnodeList() {
|
||||||
Relation rel = this.dbmap == null ? null : this.dbmap.getSubnodeRelation();
|
Relation rel = this.dbmap == null ? null : this.dbmap.getSubnodeRelation();
|
||||||
if (rel != null && rel.updateCriteria != null) {
|
if (rel != null && rel.updateCriteria != null) {
|
||||||
subnodes = new UpdateableSubnodeList(rel);
|
subnodes = new UpdateableSubnodeList(nmgr, rel);
|
||||||
} else if (rel != null && rel.autoSorted) {
|
} else if (rel != null && rel.autoSorted) {
|
||||||
subnodes = new OrderedSubnodeList(rel);
|
subnodes = new OrderedSubnodeList(nmgr, rel);
|
||||||
} else {
|
} else {
|
||||||
subnodes = new SubnodeList();
|
subnodes = new SubnodeList(nmgr, rel);
|
||||||
}
|
}
|
||||||
return subnodes;
|
return subnodes;
|
||||||
}
|
}
|
||||||
|
@ -1661,11 +1661,11 @@ public final class Node implements INode, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Return this Node's subnode list
|
||||||
*
|
*
|
||||||
*
|
* @return the subnode list
|
||||||
* @return ...
|
|
||||||
*/
|
*/
|
||||||
public List getSubnodeList() {
|
public SubnodeList getSubnodeList() {
|
||||||
return subnodes;
|
return subnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1186,6 +1186,12 @@ public final class NodeManager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
key = node.getKey();
|
key = node.getKey();
|
||||||
|
synchronized (cache) {
|
||||||
|
Node oldnode = (Node) cache.put(key, node);
|
||||||
|
if ((oldnode != null) && (oldnode.getState() != INode.INVALID)) {
|
||||||
|
cache.put(key, oldnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
key = new DbKey(rel.otherType, kstr);
|
key = new DbKey(rel.otherType, kstr);
|
||||||
}
|
}
|
||||||
|
@ -1320,7 +1326,7 @@ public final class NodeManager {
|
||||||
SubnodeList sn = (SubnodeList) groupbySubnodes.get(groupName);
|
SubnodeList sn = (SubnodeList) groupbySubnodes.get(groupName);
|
||||||
|
|
||||||
if (sn == null) {
|
if (sn == null) {
|
||||||
sn = new SubnodeList();
|
sn = new SubnodeList(safe, rel);
|
||||||
groupbySubnodes.put(groupName, sn);
|
groupbySubnodes.put(groupName, sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,49 +29,24 @@ import java.util.List;
|
||||||
* or remove-methods are called.
|
* or remove-methods are called.
|
||||||
*/
|
*/
|
||||||
public class OrderedSubnodeList extends SubnodeList {
|
public class OrderedSubnodeList extends SubnodeList {
|
||||||
HashMap views = null;
|
|
||||||
private final OrderedSubnodeList origin;
|
|
||||||
|
|
||||||
|
// the base subnode list, in case this is an ordered view
|
||||||
|
private SubnodeList origin;
|
||||||
// an array containing the order-fields
|
// an array containing the order-fields
|
||||||
private final String orderProperties[];
|
private String orderProperties[];
|
||||||
// an array containing the direction for ordering
|
// an array containing the direction for ordering
|
||||||
private final boolean orderIsDesc[];
|
private boolean orderIsDesc[];
|
||||||
|
|
||||||
// the relation which is the basis for this collection
|
|
||||||
final Relation rel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new OrderedSubnodeList. The Relation is needed
|
* Construct a new OrderedSubnodeList. The Relation is needed
|
||||||
* to get the information about the ORDERING
|
* to get the information about the ORDERING
|
||||||
*/
|
*/
|
||||||
public OrderedSubnodeList (Relation rel) {
|
public OrderedSubnodeList (WrappedNodeManager nmgr, Relation rel) {
|
||||||
this.rel = rel;
|
super(nmgr, rel);
|
||||||
this.origin = null;
|
this.origin = null;
|
||||||
// check the order of this collection for automatically sorting
|
// check the order of this collection for automatically sorting
|
||||||
// in the values in the correct order
|
// in the values in the correct order
|
||||||
if (rel.order == null) {
|
initOrder(rel.order);
|
||||||
orderProperties=null;
|
|
||||||
orderIsDesc=null;
|
|
||||||
} else {
|
|
||||||
String singleOrders[] = rel.order.split(",");
|
|
||||||
orderProperties = new String[singleOrders.length];
|
|
||||||
orderIsDesc = new boolean[singleOrders.length];
|
|
||||||
DbMapping dbm = rel.otherType;
|
|
||||||
for (int i = 0; i < singleOrders.length; i++) {
|
|
||||||
String currOrder[] = singleOrders[i].trim().split(" ");
|
|
||||||
if (currOrder[0].equalsIgnoreCase(rel.otherType.getIDField())) {
|
|
||||||
orderProperties[i]=null;
|
|
||||||
} else {
|
|
||||||
orderProperties[i] = dbm.columnNameToProperty(currOrder[0]);
|
|
||||||
}
|
|
||||||
System.err.println("ORDER PROP " + i + " IS " + orderProperties[i] + " FROM " +currOrder[0]);
|
|
||||||
if (currOrder.length < 2
|
|
||||||
|| "ASC".equalsIgnoreCase(currOrder[1]))
|
|
||||||
orderIsDesc[i]=false;
|
|
||||||
else
|
|
||||||
orderIsDesc[i]=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,36 +55,31 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
* @param expr the new order for this view
|
* @param expr the new order for this view
|
||||||
* @param rel the relation given for the origin-list
|
* @param rel the relation given for the origin-list
|
||||||
*/
|
*/
|
||||||
public OrderedSubnodeList (OrderedSubnodeList origin, String expr, Relation rel) {
|
public OrderedSubnodeList (WrappedNodeManager nmgr, Relation rel, SubnodeList origin, String expr) {
|
||||||
|
super(nmgr, rel);
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
this.rel = rel;
|
initOrder(expr);
|
||||||
if (expr==null) {
|
if (origin != null) {
|
||||||
|
sortIn(origin, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initOrder(String order) {
|
||||||
|
if (order == null) {
|
||||||
orderProperties=null;
|
orderProperties=null;
|
||||||
orderIsDesc=null;
|
orderIsDesc=null;
|
||||||
} else {
|
} else {
|
||||||
String singleOrders[] = expr.split(",");
|
String orderParts[] = order.split(",");
|
||||||
orderProperties = new String[singleOrders.length];
|
orderProperties = new String[orderParts.length];
|
||||||
orderIsDesc = new boolean[singleOrders.length];
|
orderIsDesc = new boolean[orderParts.length];
|
||||||
DbMapping dbm = rel.otherType;
|
for (int i = 0; i < orderParts.length; i++) {
|
||||||
for (int i = 0; i<singleOrders.length; i++) {
|
String part[] = orderParts[i].trim().split(" ");
|
||||||
String currOrder[] = singleOrders[i].trim().split(" ");
|
orderProperties[i] = part[0].equals("_id") ?
|
||||||
if (currOrder[0].equalsIgnoreCase("_id")) {
|
null : part[0];
|
||||||
orderProperties[i]=null;
|
orderIsDesc[i] = part.length == 2 &&
|
||||||
} else {
|
"DESC".equalsIgnoreCase(part[1]);
|
||||||
if (dbm.propertyToColumnName(currOrder[0])==null)
|
|
||||||
throw new RuntimeException ("Properties must be mapped to get an ordered collection for these properties.");
|
|
||||||
orderProperties[i]=currOrder[0];
|
|
||||||
}
|
|
||||||
if (currOrder.length < 2
|
|
||||||
|| "ASC".equalsIgnoreCase(currOrder[1]))
|
|
||||||
orderIsDesc[i]=false;
|
|
||||||
else
|
|
||||||
orderIsDesc[i]=true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (origin == null)
|
|
||||||
return;
|
|
||||||
this.sortIn(origin, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,8 +89,19 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
* @param obj element to be inserted.
|
* @param obj element to be inserted.
|
||||||
*/
|
*/
|
||||||
public boolean add(Object obj) {
|
public boolean add(Object obj) {
|
||||||
System.err.println("******** SORT-ADDING " + obj);
|
return add(obj, true);
|
||||||
return add(obj, false);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified object to the list at the given position
|
||||||
|
* @param idx the index to insert the element at
|
||||||
|
* @param obj the object t add
|
||||||
|
*/
|
||||||
|
public void add(int idx, Object obj) {
|
||||||
|
if (this.orderProperties!=null)
|
||||||
|
throw new RuntimeException ("Indexed add isn't alowed for ordered subnodes");
|
||||||
|
super.add(idx, obj);
|
||||||
|
addToViews(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,20 +111,23 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
* @param obj element to be inserted.
|
* @param obj element to be inserted.
|
||||||
*/
|
*/
|
||||||
public boolean addSorted(Object obj) {
|
public boolean addSorted(Object obj) {
|
||||||
return add(obj, true);
|
return add(obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean add(Object obj, boolean sorted) {
|
boolean add(Object obj, boolean sort) {
|
||||||
if (origin != null)
|
if (origin != null) {
|
||||||
return origin.add(obj);
|
return origin.add(obj);
|
||||||
vAdd(obj);
|
}
|
||||||
while (rel.maxSize>0 && this.size() >= rel.maxSize)
|
addToViews(obj);
|
||||||
super.remove(0);
|
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||||
|
while (maxSize > 0 && this.size() >= maxSize) {
|
||||||
|
remove(size() - 1);
|
||||||
|
}
|
||||||
// escape sorting for presorted adds and grouped nodes
|
// escape sorting for presorted adds and grouped nodes
|
||||||
if (sorted || rel.groupby != null) {
|
if (sort && (rel == null || rel.groupby == null)) {
|
||||||
super.add(obj);
|
|
||||||
} else {
|
|
||||||
sortIn(obj);
|
sortIn(obj);
|
||||||
|
} else {
|
||||||
|
super.add(obj);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -156,36 +140,23 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
// no order, just add
|
// no order, just add
|
||||||
if (this.orderProperties==null)
|
if (this.orderProperties==null)
|
||||||
return super.add(obj);
|
return super.add(obj);
|
||||||
vAdd(obj);
|
addToViews(obj);
|
||||||
long start = System.currentTimeMillis();
|
Node node = ((NodeHandle) obj).getNode(nmgr);
|
||||||
try {
|
int idx = this.determineNodePosition(node, 0);
|
||||||
int idx = this.determineNodePosition((NodeHandle) obj, 0);
|
// System.err.println("Position: " + idx);
|
||||||
System.err.println("Position: " + idx);
|
if (idx<0)
|
||||||
if (idx<0)
|
return super.add(obj);
|
||||||
return super.add(obj);
|
else
|
||||||
else
|
super.add(idx, obj);
|
||||||
super.add(idx, obj);
|
return true;
|
||||||
return true;
|
|
||||||
} finally {
|
|
||||||
System.out.println("Sortmillis: " + (System.currentTimeMillis() - start));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void vAdd (Object obj) {
|
|
||||||
if (views==null || origin!=null || views.size()<1)
|
|
||||||
return;
|
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
|
||||||
osl.sortIn(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addAll(Collection col) {
|
public boolean addAll(Collection col) {
|
||||||
return sortIn(col, true) > 0;
|
return sortIn(col, true) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void vAddAll (Collection col) {
|
private void addAllToViews (Collection col) {
|
||||||
if (views==null || origin!=null || views.size()<1)
|
if (views == null || origin != null || views.isEmpty())
|
||||||
return;
|
return;
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||||
|
@ -193,37 +164,32 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(int idx, Object obj) {
|
|
||||||
if (this.orderProperties!=null)
|
|
||||||
throw new RuntimeException ("Indexed add isn't alowed for ordered subnodes");
|
|
||||||
super.add(idx, obj);
|
|
||||||
vAdd(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all nodes contained inside the specified Collection to this
|
* Add all nodes contained inside the specified Collection to this
|
||||||
* UpdateableSubnodeList. The order of the added Nodes is asumed to
|
* UpdateableSubnodeList. The order of the added Nodes is assumed to
|
||||||
* be ordered according to the SQL-Order-Clausel given for this
|
* be ordered according to the SQL-Order-Clause given for this
|
||||||
* Subnodecollection but doesn't prevent adding of unordered Collections.
|
* Subnode collection but doesn't prevent adding of unordered Collections.
|
||||||
* Ordered Collections will be sorted in more efficient than unordered ones.
|
* Ordered Collections will be sorted in more efficiently than unordered ones.
|
||||||
|
*
|
||||||
* @param col the collection containing all elements to add in the order returned by the select-statement
|
* @param col the collection containing all elements to add in the order returned by the select-statement
|
||||||
* @param colHasDefaultOrder true if the given collection does have the default-order defined by the relation
|
* @param colHasDefaultOrder true if the given collection does have the default-order defined by the relation
|
||||||
*/
|
*/
|
||||||
public int sortIn (Collection col, boolean colHasDefaultOrder) {
|
public int sortIn (Collection col, boolean colHasDefaultOrder) {
|
||||||
vAddAll(col);
|
addAllToViews(col);
|
||||||
int cntr=0;
|
int cntr=0;
|
||||||
// there is no order specified, add on top
|
// there is no order specified, add on top
|
||||||
if (orderProperties==null) {
|
if (orderProperties == null) {
|
||||||
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
||||||
super.add(cntr, i.next());
|
super.add(cntr, i.next());
|
||||||
cntr++;
|
cntr++;
|
||||||
}
|
}
|
||||||
if (rel.maxSize > 0) {
|
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||||
int diff = this.size() - rel.maxSize;
|
if (maxSize > 0) {
|
||||||
|
int diff = this.size() - maxSize;
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
super.removeRange(this.size()-1-diff, this.size()-1);
|
super.removeRange(this.size()-1-diff, this.size()-1);
|
||||||
}
|
}
|
||||||
} else if (!colHasDefaultOrder || origin!=null) {
|
} else if (!colHasDefaultOrder || origin != null) {
|
||||||
// this collection is a view or the given collection doesn't have the
|
// this collection is a view or the given collection doesn't have the
|
||||||
// default order
|
// default order
|
||||||
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
||||||
|
@ -235,21 +201,21 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NodeHandle[] nhArr = (NodeHandle[]) col.toArray (new NodeHandle[0]);
|
NodeHandle[] nhArr = (NodeHandle[]) col.toArray (new NodeHandle[0]);
|
||||||
int locIdx=determineNodePosition(nhArr[0], 0); // determine start-point
|
Node node = nhArr[0].getNode(nmgr);
|
||||||
if (locIdx==-1)
|
int locIdx = determineNodePosition(node, 0); // determine start-point
|
||||||
locIdx=this.size();
|
if (locIdx == -1)
|
||||||
|
locIdx = this.size();
|
||||||
// int interval=Math.max(1, this.size()/2);
|
// int interval=Math.max(1, this.size()/2);
|
||||||
int addIdx=0;
|
for (int addIdx=0; addIdx < nhArr.length; addIdx++) {
|
||||||
for (; addIdx < nhArr.length; addIdx++) {
|
node = nhArr[addIdx].getNode(nmgr);
|
||||||
while (locIdx < this.size() && compareNodes(nhArr[addIdx], (NodeHandle) this.get(locIdx)) >= 0)
|
while (locIdx < this.size() &&
|
||||||
|
compareNodes(node, (NodeHandle) this.get(locIdx)) >= 0)
|
||||||
locIdx++;
|
locIdx++;
|
||||||
if (locIdx >= this.size())
|
if (locIdx < this.size()) {
|
||||||
break;
|
this.add(locIdx, nhArr[addIdx]);
|
||||||
this.add(locIdx, nhArr[addIdx]);
|
} else {
|
||||||
cntr++;
|
this.add(nhArr[addIdx]);
|
||||||
}
|
}
|
||||||
for (; addIdx < nhArr.length; addIdx++) {
|
|
||||||
this.add(nhArr[addIdx]);
|
|
||||||
cntr++;
|
cntr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,54 +223,18 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove the object specified by the given index-position
|
* remove all elements contained inside the specified collection
|
||||||
* @param idx the index-position of the NodeHandle to remove
|
|
||||||
*/
|
|
||||||
public Object remove (int idx) {
|
|
||||||
vRemove(idx);
|
|
||||||
return super.remove(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void vRemove(int idx) {
|
|
||||||
if (views==null || origin!=null || views.size()<1)
|
|
||||||
return;
|
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
|
||||||
osl.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove the given Object from this List
|
|
||||||
* @param obj the NodeHandle to remove
|
|
||||||
*/
|
|
||||||
public boolean remove (Object obj) {
|
|
||||||
vRemove(obj);
|
|
||||||
return super.remove(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void vRemove(Object obj) {
|
|
||||||
if (views==null || origin!=null || views.size()<1)
|
|
||||||
return;
|
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
|
||||||
osl.remove(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove all elements conteined inside the specified collection
|
|
||||||
* from this List
|
* from this List
|
||||||
* @param c the Collection containing all Objects to remove from this List
|
* @param c the Collection containing all Objects to remove from this List
|
||||||
* @return true if the List has been modified
|
* @return true if the List has been modified
|
||||||
*/
|
*/
|
||||||
public boolean removeAll(Collection c) {
|
public boolean removeAll(Collection c) {
|
||||||
vRemoveAll(c);
|
removeAllFromViews(c);
|
||||||
return super.removeAll(c);
|
return super.removeAll(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void vRemoveAll(Collection c) {
|
private void removeAllFromViews(Collection c) {
|
||||||
if (views==null || origin!=null || views.size()<1)
|
if (views == null || origin != null || views.isEmpty())
|
||||||
return;
|
return;
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||||
|
@ -319,12 +249,12 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
* @return true if the List has been modified
|
* @return true if the List has been modified
|
||||||
*/
|
*/
|
||||||
public boolean retainAll (Collection c) {
|
public boolean retainAll (Collection c) {
|
||||||
vRetainAll(c);
|
retainAllInViews(c);
|
||||||
return super.retainAll(c);
|
return super.retainAll(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void vRetainAll(Collection c) {
|
private void retainAllInViews(Collection c) {
|
||||||
if (views==null || origin!=null || views.size()<1)
|
if (views == null || origin != null || views.isEmpty())
|
||||||
return;
|
return;
|
||||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||||
|
@ -332,21 +262,22 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int determineNodePosition (NodeHandle nh, int startIdx) {
|
private int determineNodePosition (Node node, int startIdx) {
|
||||||
int size = this.size();
|
int size = this.size();
|
||||||
int interval = Math.max(1, (size-startIdx)/2);
|
int interval = Math.max(1, (size - startIdx) / 2);
|
||||||
boolean dirUp=true;
|
boolean dirUp=true;
|
||||||
int cntr = 0;
|
int cntr = 0;
|
||||||
|
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||||
for (int i = 0; i < size
|
for (int i = 0; i < size
|
||||||
&& (i < rel.maxSize || rel.maxSize <= 0)
|
&& (i < maxSize || maxSize <= 0)
|
||||||
&& cntr<(size*2); cntr++) { // cntr is used to avoid endless-loops which shouldn't happen
|
&& cntr < (size * 2); cntr++) { // cntr is used to avoid endless-loops which shouldn't happen
|
||||||
NodeHandle curr = (NodeHandle) this.get(i);
|
NodeHandle curr = (NodeHandle) this.get(i);
|
||||||
int comp = compareNodes(nh, curr);
|
int comp = compareNodes(node, curr);
|
||||||
// current NodeHandle is below the given NodeHandle
|
// current NodeHandle is below the given NodeHandle
|
||||||
// interval has to be 1 and
|
// interval has to be 1 and
|
||||||
// idx must be zero or the node before the current node must be higher or equal
|
// idx must be zero or the node before the current node must be higher or equal
|
||||||
// all conditions must be met to determine the correct position of a node
|
// all conditions must be met to determine the correct position of a node
|
||||||
if (comp < 0 && interval==1 && (i==0 || compareNodes(nh, (NodeHandle) this.get(i-1)) >= 0)) {
|
if (comp < 0 && interval==1 && (i==0 || compareNodes(node, (NodeHandle) this.get(i-1)) >= 0)) {
|
||||||
return i;
|
return i;
|
||||||
} else if (comp < 0) {
|
} else if (comp < 0) {
|
||||||
dirUp=false;
|
dirUp=false;
|
||||||
|
@ -359,7 +290,7 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
if (dirUp) {
|
if (dirUp) {
|
||||||
i=i+interval;
|
i=i+interval;
|
||||||
if (i >= this.size()) {
|
if (i >= this.size()) {
|
||||||
if (compareNodes(nh, (NodeHandle) this.get(size-1)) >= 0)
|
if (compareNodes(node, (NodeHandle) this.get(size-1)) >= 0)
|
||||||
break;
|
break;
|
||||||
interval = Math.max(1, (i - size-1)/2);
|
interval = Math.max(1, (i - size-1)/2);
|
||||||
i = this.size()-1;
|
i = this.size()-1;
|
||||||
|
@ -367,58 +298,58 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
interval = Math.max(1,interval/2);
|
interval = Math.max(1,interval/2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i=i-interval;
|
i = i-interval;
|
||||||
if (i < 0) { // shouldn't happen i think
|
if (i < 0) { // shouldn't happen i think
|
||||||
interval=Math.max(1,(interval+i)/2);
|
interval=Math.max(1, (interval+i)/2);
|
||||||
i=0;
|
i=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (cntr >= size*2 && size>1) {
|
if (cntr >= size * 2 && size > 1) {
|
||||||
System.err.println("determineNodePosition needed more than the allowed iterations" + this.rel.prototype);
|
System.err.println("determineNodePosition needed more than the allowed iterations");
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two nodes depending on the specified ORDER for this collection.
|
* Compare two nodes depending on the specified ORDER for this collection.
|
||||||
* @param nh1 the first NodeHandle
|
* @param node the first Node
|
||||||
* @param nh2 the second NodeHandle
|
* @param nodeHandle the second Node
|
||||||
* @return an integer lesser than zero if nh1 is less than, zero if nh1 is equal to and a value greater than zero if nh1 is bigger than nh2.
|
* @return an integer lesser than zero if nh1 is less than, zero if nh1 is equal to and a value greater than zero if nh1 is bigger than nh2.
|
||||||
*/
|
*/
|
||||||
private int compareNodes(NodeHandle nh1, NodeHandle nh2) {
|
private int compareNodes(Node node, NodeHandle nodeHandle) {
|
||||||
WrappedNodeManager wnmgr=null;
|
|
||||||
for (int i = 0; i < orderProperties.length; i++) {
|
for (int i = 0; i < orderProperties.length; i++) {
|
||||||
if (orderProperties[i]==null) {
|
if (orderProperties[i]==null) {
|
||||||
// we have the id as order-criteria-> avoid loading node
|
// we have the id as order-criteria-> avoid loading node
|
||||||
// and compare numerically instead of lexicographically
|
// and compare numerically instead of lexicographically
|
||||||
String s1 = nh1.getID();
|
String s1 = node.getID();
|
||||||
String s2 = nh2.getID();
|
String s2 = nodeHandle.getID();
|
||||||
int j = compareNumericString (s1, s2);
|
int j = compareNumericString (s1, s2);
|
||||||
if (j==0)
|
if (j == 0)
|
||||||
continue;
|
continue;
|
||||||
if (orderIsDesc[i])
|
if (orderIsDesc[i])
|
||||||
j=j*-1;
|
j = j * -1;
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
System.err.println("CHECKING PROPERTY: " + orderProperties[i] + " / " + orderIsDesc[i]);
|
Property p1 = node.getProperty(orderProperties[i]);
|
||||||
if (wnmgr == null)
|
Property p2 = nodeHandle.getNode(nmgr).getProperty(orderProperties[i]);
|
||||||
wnmgr = rel.otherType.getWrappedNodeManager();
|
|
||||||
Property p1 = nh1.getNode(wnmgr).getProperty(orderProperties[i]);
|
|
||||||
Property p2 = nh2.getNode(wnmgr).getProperty(orderProperties[i]);
|
|
||||||
System.out.println ("*** Comparing " + p1 + " - " + p2);
|
|
||||||
int j;
|
int j;
|
||||||
if (p1==null && p2==null)
|
if (p1 == null && p2 == null) {
|
||||||
continue;
|
continue;
|
||||||
else if (p1==null)
|
} else if (p1 == null) {
|
||||||
|
j = 1;
|
||||||
|
} else if (p2 == null) {
|
||||||
j = -1;
|
j = -1;
|
||||||
else
|
} else {
|
||||||
j = p1.compareTo(p2);
|
j = p1.compareTo(p2);
|
||||||
if (j == 0)
|
}
|
||||||
|
if (j == 0) {
|
||||||
continue;
|
continue;
|
||||||
if (orderIsDesc[i])
|
}
|
||||||
|
if (orderIsDesc[i]) {
|
||||||
j = j * -1;
|
j = j * -1;
|
||||||
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -451,21 +382,10 @@ public class OrderedSubnodeList extends SubnodeList {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List getOrderedView (String order) {
|
public List getOrderedView (String order) {
|
||||||
if (origin != null)
|
if (origin != null) {
|
||||||
return origin.getOrderedView(order);
|
return origin.getOrderedView(order);
|
||||||
String key = order.trim().toLowerCase();
|
} else {
|
||||||
if (key.equalsIgnoreCase(rel.order))
|
return super.getOrderedView(order);
|
||||||
return this;
|
}
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
if (views == null)
|
|
||||||
views = new HashMap();
|
|
||||||
OrderedSubnodeList osl = (OrderedSubnodeList) views.get(key);
|
|
||||||
if (osl == null) {
|
|
||||||
osl = new OrderedSubnodeList (this, order, rel);
|
|
||||||
views.put(key, osl);
|
|
||||||
System.out.println("getting view cost me " + (System.currentTimeMillis()-start) + " millis");
|
|
||||||
} else
|
|
||||||
System.out.println("getting cached view cost me " + (System.currentTimeMillis()-start) + " millis");
|
|
||||||
return osl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,9 +508,9 @@ public final class Property implements IProperty, Serializable, Cloneable, Compa
|
||||||
if (value==null && pvalue == null) {
|
if (value==null && pvalue == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (value == null) {
|
} else if (value == null) {
|
||||||
return -1;
|
|
||||||
} if (pvalue == null) {
|
|
||||||
return 1;
|
return 1;
|
||||||
|
} if (pvalue == null) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
if (type != ptype) {
|
if (type != ptype) {
|
||||||
throw new ClassCastException("uncomparable values " + this + "(" + type + ") : " + p + "(" + ptype + ")");
|
throw new ClassCastException("uncomparable values " + this + "(" + type + ") : " + p + "(" + ptype + ")");
|
||||||
|
|
|
@ -17,12 +17,34 @@
|
||||||
package helma.objectmodel.db;
|
package helma.objectmodel.db;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of ArrayList that adds an addSorted(Object) method to
|
* A subclass of ArrayList that adds an addSorted(Object) method to
|
||||||
*/
|
*/
|
||||||
public class SubnodeList extends ArrayList {
|
public class SubnodeList extends ArrayList {
|
||||||
|
|
||||||
|
WrappedNodeManager nmgr;
|
||||||
|
|
||||||
|
HashMap views = null;
|
||||||
|
Relation rel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide/disable zero argument constructor for subclasses
|
||||||
|
*/
|
||||||
|
private SubnodeList() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new subnode list
|
||||||
|
* @param nmgr
|
||||||
|
*/
|
||||||
|
public SubnodeList(WrappedNodeManager nmgr, Relation rel) {
|
||||||
|
this.nmgr = nmgr;
|
||||||
|
this.rel = rel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the specified element at the specified position in this
|
* Inserts the specified element at the specified position in this
|
||||||
* list without performing custom ordering
|
* list without performing custom ordering
|
||||||
|
@ -33,4 +55,77 @@ public class SubnodeList extends ArrayList {
|
||||||
return add(obj);
|
return add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified object to this list performing
|
||||||
|
* custom ordering
|
||||||
|
*
|
||||||
|
* @param obj element to be inserted.
|
||||||
|
*/
|
||||||
|
public boolean add(Object obj) {
|
||||||
|
addToViews(obj);
|
||||||
|
return super.add(obj);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds the specified object to the list at the given position
|
||||||
|
* @param idx the index to insert the element at
|
||||||
|
* @param obj the object t add
|
||||||
|
*/
|
||||||
|
public void add(int idx, Object obj) {
|
||||||
|
addToViews(obj);
|
||||||
|
super.add(idx, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove the object specified by the given index-position
|
||||||
|
* @param idx the index-position of the NodeHandle to remove
|
||||||
|
*/
|
||||||
|
public Object remove (int idx) {
|
||||||
|
Object obj = get(idx);
|
||||||
|
if (obj != null) {
|
||||||
|
removeFromViews(obj);
|
||||||
|
}
|
||||||
|
return super.remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove the given Object from this List
|
||||||
|
* @param obj the NodeHandle to remove
|
||||||
|
*/
|
||||||
|
public boolean remove (Object obj) {
|
||||||
|
removeFromViews(obj);
|
||||||
|
return super.remove(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeFromViews(Object obj) {
|
||||||
|
if (views == null || views.isEmpty())
|
||||||
|
return;
|
||||||
|
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||||
|
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||||
|
osl.remove(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getOrderedView (String order) {
|
||||||
|
String key = order.trim().toLowerCase();
|
||||||
|
// long start = System.currentTimeMillis();
|
||||||
|
if (views == null) {
|
||||||
|
views = new HashMap();
|
||||||
|
}
|
||||||
|
OrderedSubnodeList osl = (OrderedSubnodeList) views.get(key);
|
||||||
|
if (osl == null) {
|
||||||
|
osl = new OrderedSubnodeList (nmgr, rel, this, order);
|
||||||
|
views.put(key, osl);
|
||||||
|
}
|
||||||
|
return osl;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addToViews (Object obj) {
|
||||||
|
if (views == null || views.isEmpty())
|
||||||
|
return;
|
||||||
|
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||||
|
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||||
|
osl.sortIn(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ public class UpdateableSubnodeList extends OrderedSubnodeList {
|
||||||
* Construct a new UpdateableSubnodeList. The Relation is needed
|
* Construct a new UpdateableSubnodeList. The Relation is needed
|
||||||
* to get the information about the ORDERING and the UPDATECriteriaS
|
* to get the information about the ORDERING and the UPDATECriteriaS
|
||||||
*/
|
*/
|
||||||
public UpdateableSubnodeList (Relation rel) {
|
public UpdateableSubnodeList (WrappedNodeManager nmgr, Relation rel) {
|
||||||
super(rel);
|
super(nmgr, rel);
|
||||||
// check the update-criterias for updating this collection
|
// check the update-criterias for updating this collection
|
||||||
if (rel.updateCriteria == null) {
|
if (rel.updateCriteria == null) {
|
||||||
// criteria-field muss vom criteria-operant getrennt werden
|
// criteria-field muss vom criteria-operant getrennt werden
|
||||||
|
@ -391,7 +391,7 @@ public class UpdateableSubnodeList extends OrderedSubnodeList {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if the wrapped List is an instance of OrderedSubnodeList,
|
* if the wrapped List is an instance of OrderedSubnodeList,
|
||||||
* the sortIn-method will be used.
|
* the sortIn() method will be used.
|
||||||
*/
|
*/
|
||||||
public boolean addAll(Collection col) {
|
public boolean addAll(Collection col) {
|
||||||
return sortIn(col, true) > 0;
|
return sortIn(col, true) > 0;
|
||||||
|
|
|
@ -35,16 +35,6 @@ import java.io.IOException;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class HopObject extends ScriptableObject implements Wrapper, PropertyRecorder {
|
public class HopObject extends ScriptableObject implements Wrapper, PropertyRecorder {
|
||||||
static Method hopObjCtor;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
hopObjCtor = HopObject.class.getMethod("jsConstructor", new Class[] {
|
|
||||||
Context.class, Object[].class, Function.class, Boolean.TYPE });
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException("Error getting HopObject.jsConstructor()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String className;
|
String className;
|
||||||
INode node;
|
INode node;
|
||||||
|
@ -54,40 +44,46 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
private boolean isRecording = false;
|
private boolean isRecording = false;
|
||||||
private HashSet changedProperties;
|
private HashSet changedProperties;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new HopObject object.
|
|
||||||
*/
|
|
||||||
public HopObject() {
|
|
||||||
className = "HopObject";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new HopObject prototype.
|
* Creates a new HopObject prototype.
|
||||||
*
|
*
|
||||||
* @param cname ...
|
* @param className the prototype name
|
||||||
|
* @param core the RhinoCore
|
||||||
*/
|
*/
|
||||||
protected HopObject(String cname) {
|
protected HopObject(String className, RhinoCore core) {
|
||||||
className = cname;
|
this.className = className;
|
||||||
|
this.core = core;
|
||||||
|
setParentScope(core.global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new HopObject prototype.
|
* Creates a new HopObject.
|
||||||
*
|
*
|
||||||
* @param cname ...
|
* @param className the className
|
||||||
|
* @param proto the object's prototype
|
||||||
*/
|
*/
|
||||||
protected HopObject(String cname, Scriptable proto) {
|
protected HopObject(String className, RhinoCore core,
|
||||||
className = cname;
|
INode node, Scriptable proto) {
|
||||||
|
this(className, core);
|
||||||
|
this.node = node;
|
||||||
setPrototype(proto);
|
setPrototype(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HopObject init(Scriptable scope)
|
/**
|
||||||
|
* Initialize HopObject prototype for Rhino scope.
|
||||||
|
*
|
||||||
|
* @param core the RhinoCore
|
||||||
|
* @return the HopObject prototype
|
||||||
|
* @throws PropertyException
|
||||||
|
*/
|
||||||
|
public static HopObject init(RhinoCore core)
|
||||||
throws PropertyException {
|
throws PropertyException {
|
||||||
int attributes = READONLY | DONTENUM | PERMANENT;
|
int attributes = READONLY | DONTENUM | PERMANENT;
|
||||||
|
|
||||||
// create prototype object
|
// create prototype object
|
||||||
HopObject proto = new HopObject();
|
HopObject proto = new HopObject("HopObject", core);
|
||||||
proto.setPrototype(getObjectPrototype(scope));
|
proto.setPrototype(getObjectPrototype(core.global));
|
||||||
|
|
||||||
// install JavaScript methods and properties
|
// install JavaScript methods and properties
|
||||||
Method[] methods = HopObject.class.getDeclaredMethods();
|
Method[] methods = HopObject.class.getDeclaredMethods();
|
||||||
|
@ -109,54 +105,6 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is used as HopObject constructor from JavaScript.
|
|
||||||
*/
|
|
||||||
public static Object jsConstructor(Context cx, Object[] args,
|
|
||||||
Function ctorObj, boolean inNewExpr)
|
|
||||||
throws EvaluatorException, ScriptingException {
|
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
|
||||||
RhinoCore core = engine.core;
|
|
||||||
String protoname = ((FunctionObject) ctorObj).getFunctionName();
|
|
||||||
|
|
||||||
// if this is a java object prototype, create a new java object
|
|
||||||
// of the given class instead of a HopObject.
|
|
||||||
if (core.app.isJavaPrototype(protoname)) {
|
|
||||||
String classname = core.app.getJavaClassForPrototype(protoname);
|
|
||||||
try {
|
|
||||||
Class clazz = Class.forName(classname);
|
|
||||||
// try to get the constructor matching our arguments
|
|
||||||
Class[] argsTypes = new Class[args.length];
|
|
||||||
for (int i=0; i<argsTypes.length; i++) {
|
|
||||||
argsTypes[i] = args[i] == null ? null : args[i].getClass();
|
|
||||||
}
|
|
||||||
Constructor cnst = clazz.getConstructor(argsTypes);
|
|
||||||
// crate a new instance using the constructor
|
|
||||||
Object obj = cnst.newInstance(args);
|
|
||||||
return Context.toObject(obj, engine.global);
|
|
||||||
} catch (Exception x) {
|
|
||||||
System.err.println("Error in Java constructor: "+x);
|
|
||||||
throw new EvaluatorException(x.toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
INode node = new helma.objectmodel.db.Node(protoname, protoname,
|
|
||||||
core.app.getWrappedNodeManager());
|
|
||||||
Scriptable proto = core.getPrototype(protoname);
|
|
||||||
HopObject hobj = new HopObject(protoname, proto);
|
|
||||||
|
|
||||||
hobj.init(core, node);
|
|
||||||
if (proto != null) {
|
|
||||||
engine.invoke(hobj,
|
|
||||||
"__constructor__",
|
|
||||||
args, ScriptingEngine.ARGS_WRAP_NONE,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hobj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -177,17 +125,6 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
return toString();
|
return toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param c ...
|
|
||||||
* @param n ...
|
|
||||||
*/
|
|
||||||
public void init(RhinoCore c, INode n) {
|
|
||||||
core = c;
|
|
||||||
node = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the INode wrapped by this HopObject.
|
* Return the INode wrapped by this HopObject.
|
||||||
*
|
*
|
||||||
|
@ -217,7 +154,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
* Check if the node has been invalidated. If so, it has to be re-fetched
|
* Check if the node has been invalidated. If so, it has to be re-fetched
|
||||||
* from the db via the app's node manager.
|
* from the db via the app's node manager.
|
||||||
*/
|
*/
|
||||||
private final void checkNode() {
|
private void checkNode() {
|
||||||
if (node != null && node.getState() == INode.INVALID) {
|
if (node != null && node.getState() == INode.INVALID) {
|
||||||
if (node instanceof helma.objectmodel.db.Node) {
|
if (node instanceof helma.objectmodel.db.Node) {
|
||||||
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
|
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
|
||||||
|
@ -425,7 +362,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
|
|
||||||
if (id instanceof Number) {
|
if (id instanceof Number) {
|
||||||
n = node.getSubnodeAt(((Number) id).intValue());
|
n = node.getSubnodeAt(((Number) id).intValue());
|
||||||
} else if (id != null) {
|
} else {
|
||||||
n = node.getChildElement(id.toString());
|
n = node.getChildElement(id.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1132,16 +1069,12 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
}
|
}
|
||||||
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
|
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
|
||||||
n.loadNodes();
|
n.loadNodes();
|
||||||
List subnodes = n.getSubnodeList();
|
SubnodeList subnodes = n.getSubnodeList();
|
||||||
if (subnodes == null) {
|
if (subnodes == null) {
|
||||||
throw new RuntimeException (
|
throw new RuntimeException (
|
||||||
"getOrderedView only callable on already existing subnode-collections");
|
"getOrderedView only callable on already existing subnode-collections");
|
||||||
}
|
}
|
||||||
if (subnodes instanceof OrderedSubnodeList) {
|
return new ListViewWrapper (subnodes.getOrderedView(expr),
|
||||||
return new ListViewWrapper ((((OrderedSubnodeList) subnodes).getOrderedView(expr)),
|
|
||||||
core, n.getDbMapping().getWrappedNodeManager(), this);
|
core, n.getDbMapping().getWrappedNodeManager(), this);
|
||||||
}
|
|
||||||
throw new RuntimeException (
|
|
||||||
"getOrderedView only callable on OrderedSubnodeList");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
149
src/helma/scripting/rhino/HopObjectCtor.java
Normal file
149
src/helma/scripting/rhino/HopObjectCtor.java
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* 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 org.mozilla.javascript.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
import helma.objectmodel.db.DbMapping;
|
||||||
|
import helma.objectmodel.db.DbKey;
|
||||||
|
|
||||||
|
public class HopObjectCtor extends FunctionObject {
|
||||||
|
|
||||||
|
// init flag to trigger prototype compilation on
|
||||||
|
// static constructor property access
|
||||||
|
boolean initialized;
|
||||||
|
RhinoCore core;
|
||||||
|
|
||||||
|
static Method hopObjCtor;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
hopObjCtor = HopObjectCtor.class.getMethod("jsConstructor", new Class[] {
|
||||||
|
Context.class, Object[].class, Function.class, Boolean.TYPE });
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException("Error getting HopObjectCtor.jsConstructor()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final int attr = ScriptableObject.DONTENUM |
|
||||||
|
ScriptableObject.PERMANENT |
|
||||||
|
ScriptableObject.READONLY;
|
||||||
|
/**
|
||||||
|
* Create and install a HopObject constructor.
|
||||||
|
* Part of this is copied from o.m.j.FunctionObject.addAsConstructor().
|
||||||
|
*
|
||||||
|
* @param prototype
|
||||||
|
*/
|
||||||
|
public HopObjectCtor(String protoName, RhinoCore core, Scriptable prototype) {
|
||||||
|
super(protoName, hopObjCtor, core.global);
|
||||||
|
this.core = core;
|
||||||
|
// Scriptable ps = prototype.getParentScope();
|
||||||
|
addAsConstructor(core.global, prototype);
|
||||||
|
// prototype.setParentScope(ps);
|
||||||
|
defineProperty("getById", new GetById(), attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used as HopObject constructor from JavaScript.
|
||||||
|
*/
|
||||||
|
public static Object jsConstructor(Context cx, Object[] args,
|
||||||
|
Function ctorObj, boolean inNewExpr)
|
||||||
|
throws JavaScriptException {
|
||||||
|
HopObjectCtor ctor = (HopObjectCtor) ctorObj;
|
||||||
|
RhinoCore core = ctor.core;
|
||||||
|
String protoname = ctor.getFunctionName();
|
||||||
|
|
||||||
|
// if this is a java object prototype, create a new java object
|
||||||
|
// of the given class instead of a HopObject.
|
||||||
|
if (core.app.isJavaPrototype(protoname)) {
|
||||||
|
String classname = core.app.getJavaClassForPrototype(protoname);
|
||||||
|
try {
|
||||||
|
Class clazz = Class.forName(classname);
|
||||||
|
// try to get the constructor matching our arguments
|
||||||
|
Class[] argsTypes = new Class[args.length];
|
||||||
|
for (int i=0; i<argsTypes.length; i++) {
|
||||||
|
argsTypes[i] = args[i] == null ? null : args[i].getClass();
|
||||||
|
}
|
||||||
|
Constructor cnst = clazz.getConstructor(argsTypes);
|
||||||
|
// crate a new instance using the constructor
|
||||||
|
Object obj = cnst.newInstance(args);
|
||||||
|
return Context.toObject(obj, core.global);
|
||||||
|
} catch (Exception x) {
|
||||||
|
System.err.println("Error in Java constructor: "+x);
|
||||||
|
throw new EvaluatorException(x.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
INode node = new helma.objectmodel.db.Node(protoname, protoname,
|
||||||
|
core.app.getWrappedNodeManager());
|
||||||
|
Scriptable proto = core.getPrototype(protoname);
|
||||||
|
HopObject hobj = new HopObject(protoname, core, node, proto);
|
||||||
|
|
||||||
|
if (proto != null) {
|
||||||
|
Object f = ScriptableObject.getProperty(proto, "__constructor__");
|
||||||
|
if (f instanceof Function) {
|
||||||
|
((Function) f).call(cx, core.global, hobj, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hobj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String name, Scriptable start) {
|
||||||
|
if (!initialized && !"prototype".equals(name)) {
|
||||||
|
// trigger prototype compilation on static
|
||||||
|
// constructor property access
|
||||||
|
initialized = true;
|
||||||
|
core.getPrototype(functionName);
|
||||||
|
}
|
||||||
|
return super.get(name, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetById extends BaseFunction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve any persistent HopObject by type name and id.
|
||||||
|
*
|
||||||
|
* @return the HopObject or null if it doesn't exist
|
||||||
|
*/
|
||||||
|
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
|
||||||
|
if (args.length < 1 || args.length > 2)
|
||||||
|
throw new IllegalArgumentException("Wrong number of arguments in getById()");
|
||||||
|
// If second argument is provided, use it as type name.
|
||||||
|
// Otherwise, use our own type name.
|
||||||
|
String type = args.length == 1 ?
|
||||||
|
HopObjectCtor.this.getFunctionName() :
|
||||||
|
Context.toString(args[1]);
|
||||||
|
|
||||||
|
DbMapping dbmap = core.app.getDbMapping(type);
|
||||||
|
if (dbmap == null)
|
||||||
|
return null;
|
||||||
|
Object node = null;
|
||||||
|
try {
|
||||||
|
DbKey key = new DbKey(dbmap, Context.toString(args[0]));
|
||||||
|
node = core.app.getNodeManager().getNode(key);
|
||||||
|
} catch (Exception x) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return node == null ? null : Context.toObject(node, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -46,6 +46,26 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
||||||
final HopObject hObj;
|
final HopObject hObj;
|
||||||
INode node;
|
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) {
|
ListViewWrapper (List list, RhinoCore core, WrappedNodeManager wnm, HopObject hObj) {
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
throw new IllegalArgumentException ("ListWrapper unable to wrap null list.");
|
throw new IllegalArgumentException ("ListWrapper unable to wrap null list.");
|
||||||
|
@ -55,13 +75,20 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
||||||
this.wnm = wnm;
|
this.wnm = wnm;
|
||||||
this.hObj = hObj;
|
this.hObj = hObj;
|
||||||
this.node = hObj.node;
|
this.node = hObj.node;
|
||||||
init();
|
if (listViewProto == null) {
|
||||||
|
listViewProto = new ListViewWrapper();
|
||||||
|
listViewProto.init();
|
||||||
|
}
|
||||||
|
setPrototype(listViewProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
/**
|
||||||
|
* Init JS functions from methods.
|
||||||
|
*/
|
||||||
|
void init() {
|
||||||
int attributes = READONLY | DONTENUM | PERMANENT;
|
int attributes = READONLY | DONTENUM | PERMANENT;
|
||||||
|
|
||||||
Method[] methods = this.getClass().getDeclaredMethods();
|
Method[] methods = getClass().getDeclaredMethods();
|
||||||
for (int i=0; i<methods.length; i++) {
|
for (int i=0; i<methods.length; i++) {
|
||||||
String methodName = methods[i].getName();
|
String methodName = methods[i].getName();
|
||||||
|
|
||||||
|
@ -70,7 +97,6 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
||||||
FunctionObject func = new FunctionObject(methodName,
|
FunctionObject func = new FunctionObject(methodName,
|
||||||
methods[i], this);
|
methods[i], this);
|
||||||
this.defineProperty(methodName, func, attributes);
|
this.defineProperty(methodName, func, attributes);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,9 +124,7 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
||||||
|
|
||||||
// return HopObject in case of a NodeHandle
|
// return HopObject in case of a NodeHandle
|
||||||
if (obj instanceof NodeHandle) {
|
if (obj instanceof NodeHandle) {
|
||||||
HopObject hObj = new HopObject();
|
return Context.toObject(((NodeHandle) obj).getNode(wnm), core.global);
|
||||||
hObj.init(core, ((NodeHandle) obj).getNode(wnm));
|
|
||||||
return hObj;
|
|
||||||
} else if (!(obj instanceof Scriptable)) {
|
} else if (!(obj instanceof Scriptable)) {
|
||||||
// do NOT wrap primitives - otherwise they'll be wrapped as Objects,
|
// do NOT wrap primitives - otherwise they'll be wrapped as Objects,
|
||||||
// which makes them unusable for many purposes (e.g. ==)
|
// which makes them unusable for many purposes (e.g. ==)
|
||||||
|
|
|
@ -113,7 +113,7 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
|
|
||||||
pathProto = new PathWrapper(this);
|
pathProto = new PathWrapper(this);
|
||||||
|
|
||||||
hopObjectProto = HopObject.init(global);
|
hopObjectProto = HopObject.init(this);
|
||||||
// use lazy loaded constructors for all extension objects that
|
// use lazy loaded constructors for all extension objects that
|
||||||
// adhere to the ScriptableObject.defineClass() protocol
|
// adhere to the ScriptableObject.defineClass() protocol
|
||||||
new LazilyLoadedCtor(global, "File",
|
new LazilyLoadedCtor(global, "File",
|
||||||
|
@ -207,10 +207,9 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
} else if ("hopobject".equals(lowerCaseName)) {
|
} else if ("hopobject".equals(lowerCaseName)) {
|
||||||
op = hopObjectProto;
|
op = hopObjectProto;
|
||||||
} else {
|
} else {
|
||||||
op = new HopObject(name);
|
op = new HopObject(name, this);
|
||||||
op.setParentScope(global);
|
|
||||||
}
|
}
|
||||||
type = registerPrototype(prototype, op);
|
registerPrototype(prototype, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register a constructor for all types except global.
|
// Register a constructor for all types except global.
|
||||||
|
@ -218,13 +217,10 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
// the actual (scripted) constructor on it.
|
// the actual (scripted) constructor on it.
|
||||||
if (!"global".equals(lowerCaseName)) {
|
if (!"global".equals(lowerCaseName)) {
|
||||||
try {
|
try {
|
||||||
FunctionObject fo = new FunctionObject(name, HopObject.hopObjCtor, global);
|
new HopObjectCtor(name, this, op);
|
||||||
fo.addAsConstructor(global, op);
|
op.setParentScope(global);
|
||||||
// add static getById() function
|
} catch (Exception x) {
|
||||||
fo.defineProperty("getById", new GetById(name), GetById.ATTRIBUTES);
|
app.logError("Error adding ctor for " + name, x);
|
||||||
} catch (Exception ignore) {
|
|
||||||
System.err.println("Error adding ctor for " + name + ": " + ignore);
|
|
||||||
ignore.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,58 +290,52 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
* here is to check for update those prototypes which already have been compiled
|
* here is to check for update those prototypes which already have been compiled
|
||||||
* before. Others will be updated/compiled on demand.
|
* before. Others will be updated/compiled on demand.
|
||||||
*/
|
*/
|
||||||
public void updatePrototypes() throws IOException {
|
public synchronized void updatePrototypes() throws IOException {
|
||||||
if ((System.currentTimeMillis() - lastUpdate) < 1000L + updateSnooze) {
|
if ((System.currentTimeMillis() - lastUpdate) < 1000L + updateSnooze) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(this) {
|
// init prototypes and/or update prototype checksums
|
||||||
if ((System.currentTimeMillis() - lastUpdate) < 1000L + updateSnooze) {
|
app.typemgr.checkPrototypes();
|
||||||
return;
|
|
||||||
|
// get a collection of all prototypes (code directories)
|
||||||
|
Collection protos = app.getPrototypes();
|
||||||
|
|
||||||
|
// in order to respect inter-prototype dependencies, we try to update
|
||||||
|
// the global prototype before all other prototypes, and parent
|
||||||
|
// prototypes before their descendants.
|
||||||
|
|
||||||
|
HashSet checked = new HashSet(protos.size() * 2);
|
||||||
|
|
||||||
|
TypeInfo type = (TypeInfo) prototypes.get("global");
|
||||||
|
|
||||||
|
if (type != null) {
|
||||||
|
updatePrototype(type, checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator i = protos.iterator(); i.hasNext();) {
|
||||||
|
Prototype proto = (Prototype) i.next();
|
||||||
|
|
||||||
|
if (checked.contains(proto)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init prototypes and/or update prototype checksums
|
type = (TypeInfo) prototypes.get(proto.getLowerCaseName());
|
||||||
app.typemgr.checkPrototypes();
|
|
||||||
|
|
||||||
// get a collection of all prototypes (code directories)
|
if (type == null) {
|
||||||
Collection protos = app.getPrototypes();
|
// a prototype we don't know anything about yet. Init local update info.
|
||||||
|
initPrototype(proto);
|
||||||
// in order to respect inter-prototype dependencies, we try to update
|
} else if (type.lastUpdate > -1) {
|
||||||
// the global prototype before all other prototypes, and parent
|
// only need to update prototype if it has already been initialized.
|
||||||
// prototypes before their descendants.
|
// otherwise, this will be done on demand.
|
||||||
|
|
||||||
HashSet checked = new HashSet(protos.size() * 2);
|
|
||||||
|
|
||||||
TypeInfo type = (TypeInfo) prototypes.get("global");
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
updatePrototype(type, checked);
|
updatePrototype(type, checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator i = protos.iterator(); i.hasNext();) {
|
|
||||||
Prototype proto = (Prototype) i.next();
|
|
||||||
|
|
||||||
if (checked.contains(proto)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = (TypeInfo) prototypes.get(proto.getLowerCaseName());
|
|
||||||
|
|
||||||
if (type == null) {
|
|
||||||
// a prototype we don't know anything about yet. Init local update info.
|
|
||||||
initPrototype(proto);
|
|
||||||
} else if (type.lastUpdate > -1) {
|
|
||||||
// only need to update prototype if it has already been initialized.
|
|
||||||
// otherwise, this will be done on demand.
|
|
||||||
updatePrototype(type, checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastUpdate = System.currentTimeMillis();
|
|
||||||
// max updateSnooze is 4 seconds, reached after 66.6 idle minutes
|
|
||||||
long newSnooze = (lastUpdate - app.typemgr.getLastCodeUpdate()) / 1000;
|
|
||||||
updateSnooze = Math.min(4000, Math.max(0, newSnooze));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastUpdate = System.currentTimeMillis();
|
||||||
|
// max updateSnooze is 4 seconds, reached after 66.6 idle minutes
|
||||||
|
long newSnooze = (lastUpdate - app.typemgr.getLastCodeUpdate()) / 1000;
|
||||||
|
updateSnooze = Math.min(4000, Math.max(0, newSnooze));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -638,8 +628,7 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esn = new HopObject(protoname, op);
|
esn = new HopObject(protoname, this, n, op);
|
||||||
esn.init(this, n);
|
|
||||||
|
|
||||||
wrappercache.put(n, esn);
|
wrappercache.put(n, esn);
|
||||||
}
|
}
|
||||||
|
@ -1077,41 +1066,7 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
} else {
|
} else {
|
||||||
df = new DecimalFormat("#,##0.00");
|
df = new DecimalFormat("#,##0.00");
|
||||||
}
|
}
|
||||||
return df.format(ScriptRuntime.toNumber(thisObj)).toString();
|
return df.format(ScriptRuntime.toNumber(thisObj));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GetById extends BaseFunction {
|
|
||||||
static final int ATTRIBUTES = DONTENUM | PERMANENT | READONLY;
|
|
||||||
String typeName;
|
|
||||||
|
|
||||||
public GetById(String typeName) {
|
|
||||||
this.typeName = typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve any persistent HopObject by type name and id.
|
|
||||||
*
|
|
||||||
* @return the HopObject or null if it doesn't exist
|
|
||||||
*/
|
|
||||||
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
|
|
||||||
if (args.length < 1 || args.length > 2)
|
|
||||||
throw new IllegalArgumentException("Wrong number of arguments in getById()");
|
|
||||||
// If second argument is provided, use it as type name.
|
|
||||||
// Otherwise, use our own type name.
|
|
||||||
String type = args.length == 1 ? typeName: Context.toString(args[1]);
|
|
||||||
|
|
||||||
DbMapping dbmap = app.getDbMapping(type);
|
|
||||||
if (dbmap == null)
|
|
||||||
return null;
|
|
||||||
Object node = null;
|
|
||||||
try {
|
|
||||||
DbKey key = new DbKey(dbmap, Context.toString(args[0]));
|
|
||||||
node = app.getNodeManager().getNode(key);
|
|
||||||
} catch (Exception x) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return node == null ? null : Context.toObject(node, this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue