* 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();
|
||||
|
||||
if (subnodes == null) {
|
||||
subnodes = new SubnodeList();
|
||||
subnodes = new SubnodeList(nmgr, dbmap.getSubnodeRelation());
|
||||
}
|
||||
|
||||
if (create || subnodes.contains(new NodeHandle(new SyntheticKey(getKey(), sid)))) {
|
||||
|
@ -1582,11 +1582,11 @@ public final class Node implements INode, Serializable {
|
|||
public SubnodeList createSubnodeList() {
|
||||
Relation rel = this.dbmap == null ? null : this.dbmap.getSubnodeRelation();
|
||||
if (rel != null && rel.updateCriteria != null) {
|
||||
subnodes = new UpdateableSubnodeList(rel);
|
||||
subnodes = new UpdateableSubnodeList(nmgr, rel);
|
||||
} else if (rel != null && rel.autoSorted) {
|
||||
subnodes = new OrderedSubnodeList(rel);
|
||||
subnodes = new OrderedSubnodeList(nmgr, rel);
|
||||
} else {
|
||||
subnodes = new SubnodeList();
|
||||
subnodes = new SubnodeList(nmgr, rel);
|
||||
}
|
||||
return subnodes;
|
||||
}
|
||||
|
@ -1661,11 +1661,11 @@ public final class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return this Node's subnode list
|
||||
*
|
||||
*
|
||||
* @return ...
|
||||
* @return the subnode list
|
||||
*/
|
||||
public List getSubnodeList() {
|
||||
public SubnodeList getSubnodeList() {
|
||||
return subnodes;
|
||||
}
|
||||
|
||||
|
|
|
@ -1186,6 +1186,12 @@ public final class NodeManager {
|
|||
continue;
|
||||
}
|
||||
key = node.getKey();
|
||||
synchronized (cache) {
|
||||
Node oldnode = (Node) cache.put(key, node);
|
||||
if ((oldnode != null) && (oldnode.getState() != INode.INVALID)) {
|
||||
cache.put(key, oldnode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
key = new DbKey(rel.otherType, kstr);
|
||||
}
|
||||
|
@ -1320,7 +1326,7 @@ public final class NodeManager {
|
|||
SubnodeList sn = (SubnodeList) groupbySubnodes.get(groupName);
|
||||
|
||||
if (sn == null) {
|
||||
sn = new SubnodeList();
|
||||
sn = new SubnodeList(safe, rel);
|
||||
groupbySubnodes.put(groupName, sn);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,49 +29,24 @@ import java.util.List;
|
|||
* or remove-methods are called.
|
||||
*/
|
||||
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
|
||||
private final String orderProperties[];
|
||||
private String orderProperties[];
|
||||
// an array containing the direction for ordering
|
||||
private final boolean orderIsDesc[];
|
||||
|
||||
// the relation which is the basis for this collection
|
||||
final Relation rel;
|
||||
private boolean orderIsDesc[];
|
||||
|
||||
/**
|
||||
* Construct a new OrderedSubnodeList. The Relation is needed
|
||||
* to get the information about the ORDERING
|
||||
*/
|
||||
public OrderedSubnodeList (Relation rel) {
|
||||
this.rel = rel;
|
||||
public OrderedSubnodeList (WrappedNodeManager nmgr, Relation rel) {
|
||||
super(nmgr, rel);
|
||||
this.origin = null;
|
||||
// check the order of this collection for automatically sorting
|
||||
// in the values in the correct order
|
||||
if (rel.order == null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
initOrder(rel.order);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,36 +55,31 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
* @param expr the new order for this view
|
||||
* @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.rel = rel;
|
||||
if (expr==null) {
|
||||
initOrder(expr);
|
||||
if (origin != null) {
|
||||
sortIn(origin, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void initOrder(String order) {
|
||||
if (order == null) {
|
||||
orderProperties=null;
|
||||
orderIsDesc=null;
|
||||
} else {
|
||||
String singleOrders[] = expr.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("_id")) {
|
||||
orderProperties[i]=null;
|
||||
} else {
|
||||
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;
|
||||
String orderParts[] = order.split(",");
|
||||
orderProperties = new String[orderParts.length];
|
||||
orderIsDesc = new boolean[orderParts.length];
|
||||
for (int i = 0; i < orderParts.length; i++) {
|
||||
String part[] = orderParts[i].trim().split(" ");
|
||||
orderProperties[i] = part[0].equals("_id") ?
|
||||
null : part[0];
|
||||
orderIsDesc[i] = part.length == 2 &&
|
||||
"DESC".equalsIgnoreCase(part[1]);
|
||||
}
|
||||
}
|
||||
if (origin == null)
|
||||
return;
|
||||
this.sortIn(origin, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,8 +89,19 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
* @param obj element to be inserted.
|
||||
*/
|
||||
public boolean add(Object obj) {
|
||||
System.err.println("******** SORT-ADDING " + obj);
|
||||
return add(obj, false);
|
||||
return add(obj, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public boolean addSorted(Object obj) {
|
||||
return add(obj, true);
|
||||
return add(obj, false);
|
||||
}
|
||||
|
||||
private boolean add(Object obj, boolean sorted) {
|
||||
if (origin != null)
|
||||
boolean add(Object obj, boolean sort) {
|
||||
if (origin != null) {
|
||||
return origin.add(obj);
|
||||
vAdd(obj);
|
||||
while (rel.maxSize>0 && this.size() >= rel.maxSize)
|
||||
super.remove(0);
|
||||
}
|
||||
addToViews(obj);
|
||||
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||
while (maxSize > 0 && this.size() >= maxSize) {
|
||||
remove(size() - 1);
|
||||
}
|
||||
// escape sorting for presorted adds and grouped nodes
|
||||
if (sorted || rel.groupby != null) {
|
||||
super.add(obj);
|
||||
} else {
|
||||
if (sort && (rel == null || rel.groupby == null)) {
|
||||
sortIn(obj);
|
||||
} else {
|
||||
super.add(obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -156,36 +140,23 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
// no order, just add
|
||||
if (this.orderProperties==null)
|
||||
return super.add(obj);
|
||||
vAdd(obj);
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
int idx = this.determineNodePosition((NodeHandle) obj, 0);
|
||||
System.err.println("Position: " + idx);
|
||||
if (idx<0)
|
||||
return super.add(obj);
|
||||
else
|
||||
super.add(idx, obj);
|
||||
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);
|
||||
}
|
||||
addToViews(obj);
|
||||
Node node = ((NodeHandle) obj).getNode(nmgr);
|
||||
int idx = this.determineNodePosition(node, 0);
|
||||
// System.err.println("Position: " + idx);
|
||||
if (idx<0)
|
||||
return super.add(obj);
|
||||
else
|
||||
super.add(idx, obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean addAll(Collection col) {
|
||||
return sortIn(col, true) > 0;
|
||||
}
|
||||
|
||||
private void vAddAll (Collection col) {
|
||||
if (views==null || origin!=null || views.size()<1)
|
||||
private void addAllToViews (Collection col) {
|
||||
if (views == null || origin != null || views.isEmpty())
|
||||
return;
|
||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||
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
|
||||
* UpdateableSubnodeList. The order of the added Nodes is asumed to
|
||||
* be ordered according to the SQL-Order-Clausel given for this
|
||||
* Subnodecollection but doesn't prevent adding of unordered Collections.
|
||||
* Ordered Collections will be sorted in more efficient than unordered ones.
|
||||
* UpdateableSubnodeList. The order of the added Nodes is assumed to
|
||||
* be ordered according to the SQL-Order-Clause given for this
|
||||
* Subnode collection but doesn't prevent adding of unordered Collections.
|
||||
* 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 colHasDefaultOrder true if the given collection does have the default-order defined by the relation
|
||||
*/
|
||||
public int sortIn (Collection col, boolean colHasDefaultOrder) {
|
||||
vAddAll(col);
|
||||
addAllToViews(col);
|
||||
int cntr=0;
|
||||
// there is no order specified, add on top
|
||||
if (orderProperties==null) {
|
||||
if (orderProperties == null) {
|
||||
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
||||
super.add(cntr, i.next());
|
||||
cntr++;
|
||||
}
|
||||
if (rel.maxSize > 0) {
|
||||
int diff = this.size() - rel.maxSize;
|
||||
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||
if (maxSize > 0) {
|
||||
int diff = this.size() - maxSize;
|
||||
if (diff > 0)
|
||||
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
|
||||
// default order
|
||||
for (Iterator i = col.iterator(); i.hasNext(); ) {
|
||||
|
@ -235,21 +201,21 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
}
|
||||
} else {
|
||||
NodeHandle[] nhArr = (NodeHandle[]) col.toArray (new NodeHandle[0]);
|
||||
int locIdx=determineNodePosition(nhArr[0], 0); // determine start-point
|
||||
if (locIdx==-1)
|
||||
locIdx=this.size();
|
||||
Node node = nhArr[0].getNode(nmgr);
|
||||
int locIdx = determineNodePosition(node, 0); // determine start-point
|
||||
if (locIdx == -1)
|
||||
locIdx = this.size();
|
||||
// int interval=Math.max(1, this.size()/2);
|
||||
int addIdx=0;
|
||||
for (; addIdx < nhArr.length; addIdx++) {
|
||||
while (locIdx < this.size() && compareNodes(nhArr[addIdx], (NodeHandle) this.get(locIdx)) >= 0)
|
||||
for (int addIdx=0; addIdx < nhArr.length; addIdx++) {
|
||||
node = nhArr[addIdx].getNode(nmgr);
|
||||
while (locIdx < this.size() &&
|
||||
compareNodes(node, (NodeHandle) this.get(locIdx)) >= 0)
|
||||
locIdx++;
|
||||
if (locIdx >= this.size())
|
||||
break;
|
||||
this.add(locIdx, nhArr[addIdx]);
|
||||
cntr++;
|
||||
}
|
||||
for (; addIdx < nhArr.length; addIdx++) {
|
||||
this.add(nhArr[addIdx]);
|
||||
if (locIdx < this.size()) {
|
||||
this.add(locIdx, nhArr[addIdx]);
|
||||
} else {
|
||||
this.add(nhArr[addIdx]);
|
||||
}
|
||||
cntr++;
|
||||
}
|
||||
}
|
||||
|
@ -257,54 +223,18 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
}
|
||||
|
||||
/**
|
||||
* remove the object specified by the given index-position
|
||||
* @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
|
||||
* remove all elements contained inside the specified collection
|
||||
* from this List
|
||||
* @param c the Collection containing all Objects to remove from this List
|
||||
* @return true if the List has been modified
|
||||
*/
|
||||
public boolean removeAll(Collection c) {
|
||||
vRemoveAll(c);
|
||||
removeAllFromViews(c);
|
||||
return super.removeAll(c);
|
||||
}
|
||||
|
||||
private void vRemoveAll(Collection c) {
|
||||
if (views==null || origin!=null || views.size()<1)
|
||||
private void removeAllFromViews(Collection c) {
|
||||
if (views == null || origin != null || views.isEmpty())
|
||||
return;
|
||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||
OrderedSubnodeList osl = (OrderedSubnodeList) i.next();
|
||||
|
@ -319,12 +249,12 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
* @return true if the List has been modified
|
||||
*/
|
||||
public boolean retainAll (Collection c) {
|
||||
vRetainAll(c);
|
||||
retainAllInViews(c);
|
||||
return super.retainAll(c);
|
||||
}
|
||||
|
||||
private void vRetainAll(Collection c) {
|
||||
if (views==null || origin!=null || views.size()<1)
|
||||
private void retainAllInViews(Collection c) {
|
||||
if (views == null || origin != null || views.isEmpty())
|
||||
return;
|
||||
for (Iterator i = views.values().iterator(); i.hasNext(); ) {
|
||||
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 interval = Math.max(1, (size-startIdx)/2);
|
||||
int interval = Math.max(1, (size - startIdx) / 2);
|
||||
boolean dirUp=true;
|
||||
int cntr = 0;
|
||||
int maxSize = rel == null ? 0 : rel.maxSize;
|
||||
for (int i = 0; i < size
|
||||
&& (i < rel.maxSize || rel.maxSize <= 0)
|
||||
&& cntr<(size*2); cntr++) { // cntr is used to avoid endless-loops which shouldn't happen
|
||||
&& (i < maxSize || maxSize <= 0)
|
||||
&& cntr < (size * 2); cntr++) { // cntr is used to avoid endless-loops which shouldn't happen
|
||||
NodeHandle curr = (NodeHandle) this.get(i);
|
||||
int comp = compareNodes(nh, curr);
|
||||
int comp = compareNodes(node, curr);
|
||||
// current NodeHandle is below the given NodeHandle
|
||||
// interval has to be 1 and
|
||||
// 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
|
||||
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;
|
||||
} else if (comp < 0) {
|
||||
dirUp=false;
|
||||
|
@ -359,7 +290,7 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
if (dirUp) {
|
||||
i=i+interval;
|
||||
if (i >= this.size()) {
|
||||
if (compareNodes(nh, (NodeHandle) this.get(size-1)) >= 0)
|
||||
if (compareNodes(node, (NodeHandle) this.get(size-1)) >= 0)
|
||||
break;
|
||||
interval = Math.max(1, (i - size-1)/2);
|
||||
i = this.size()-1;
|
||||
|
@ -367,58 +298,58 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
interval = Math.max(1,interval/2);
|
||||
}
|
||||
} else {
|
||||
i=i-interval;
|
||||
i = i-interval;
|
||||
if (i < 0) { // shouldn't happen i think
|
||||
interval=Math.max(1,(interval+i)/2);
|
||||
interval=Math.max(1, (interval+i)/2);
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (cntr >= size*2 && size>1) {
|
||||
System.err.println("determineNodePosition needed more than the allowed iterations" + this.rel.prototype);
|
||||
if (cntr >= size * 2 && size > 1) {
|
||||
System.err.println("determineNodePosition needed more than the allowed iterations");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two nodes depending on the specified ORDER for this collection.
|
||||
* @param nh1 the first NodeHandle
|
||||
* @param nh2 the second NodeHandle
|
||||
* @param node the first Node
|
||||
* @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.
|
||||
*/
|
||||
private int compareNodes(NodeHandle nh1, NodeHandle nh2) {
|
||||
WrappedNodeManager wnmgr=null;
|
||||
private int compareNodes(Node node, NodeHandle nodeHandle) {
|
||||
for (int i = 0; i < orderProperties.length; i++) {
|
||||
if (orderProperties[i]==null) {
|
||||
// we have the id as order-criteria-> avoid loading node
|
||||
// and compare numerically instead of lexicographically
|
||||
String s1 = nh1.getID();
|
||||
String s2 = nh2.getID();
|
||||
String s1 = node.getID();
|
||||
String s2 = nodeHandle.getID();
|
||||
int j = compareNumericString (s1, s2);
|
||||
if (j==0)
|
||||
if (j == 0)
|
||||
continue;
|
||||
if (orderIsDesc[i])
|
||||
j=j*-1;
|
||||
j = j * -1;
|
||||
return j;
|
||||
}
|
||||
System.err.println("CHECKING PROPERTY: " + orderProperties[i] + " / " + orderIsDesc[i]);
|
||||
if (wnmgr == null)
|
||||
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);
|
||||
Property p1 = node.getProperty(orderProperties[i]);
|
||||
Property p2 = nodeHandle.getNode(nmgr).getProperty(orderProperties[i]);
|
||||
int j;
|
||||
if (p1==null && p2==null)
|
||||
if (p1 == null && p2 == null) {
|
||||
continue;
|
||||
else if (p1==null)
|
||||
} else if (p1 == null) {
|
||||
j = 1;
|
||||
} else if (p2 == null) {
|
||||
j = -1;
|
||||
else
|
||||
} else {
|
||||
j = p1.compareTo(p2);
|
||||
if (j == 0)
|
||||
}
|
||||
if (j == 0) {
|
||||
continue;
|
||||
if (orderIsDesc[i])
|
||||
}
|
||||
if (orderIsDesc[i]) {
|
||||
j = j * -1;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
return -1;
|
||||
|
@ -451,21 +382,10 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
}
|
||||
|
||||
public List getOrderedView (String order) {
|
||||
if (origin != null)
|
||||
if (origin != null) {
|
||||
return origin.getOrderedView(order);
|
||||
String key = order.trim().toLowerCase();
|
||||
if (key.equalsIgnoreCase(rel.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;
|
||||
} else {
|
||||
return super.getOrderedView(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -508,9 +508,9 @@ public final class Property implements IProperty, Serializable, Cloneable, Compa
|
|||
if (value==null && pvalue == null) {
|
||||
return 0;
|
||||
} else if (value == null) {
|
||||
return -1;
|
||||
} if (pvalue == null) {
|
||||
return 1;
|
||||
} if (pvalue == null) {
|
||||
return -1;
|
||||
}
|
||||
if (type != ptype) {
|
||||
throw new ClassCastException("uncomparable values " + this + "(" + type + ") : " + p + "(" + ptype + ")");
|
||||
|
|
|
@ -17,12 +17,34 @@
|
|||
package helma.objectmodel.db;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
* list without performing custom ordering
|
||||
|
@ -33,4 +55,77 @@ public class SubnodeList extends ArrayList {
|
|||
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
|
||||
* to get the information about the ORDERING and the UPDATECriteriaS
|
||||
*/
|
||||
public UpdateableSubnodeList (Relation rel) {
|
||||
super(rel);
|
||||
public UpdateableSubnodeList (WrappedNodeManager nmgr, Relation rel) {
|
||||
super(nmgr, rel);
|
||||
// check the update-criterias for updating this collection
|
||||
if (rel.updateCriteria == null) {
|
||||
// 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,
|
||||
* the sortIn-method will be used.
|
||||
* the sortIn() method will be used.
|
||||
*/
|
||||
public boolean addAll(Collection col) {
|
||||
return sortIn(col, true) > 0;
|
||||
|
|
|
@ -35,16 +35,6 @@ import java.io.IOException;
|
|||
*
|
||||
*/
|
||||
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;
|
||||
INode node;
|
||||
|
@ -54,40 +44,46 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
private boolean isRecording = false;
|
||||
private HashSet changedProperties;
|
||||
|
||||
/**
|
||||
* Creates a new HopObject object.
|
||||
*/
|
||||
public HopObject() {
|
||||
className = "HopObject";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HopObject prototype.
|
||||
*
|
||||
* @param cname ...
|
||||
* @param className the prototype name
|
||||
* @param core the RhinoCore
|
||||
*/
|
||||
protected HopObject(String cname) {
|
||||
className = cname;
|
||||
protected HopObject(String className, RhinoCore core) {
|
||||
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) {
|
||||
className = cname;
|
||||
protected HopObject(String className, RhinoCore core,
|
||||
INode node, Scriptable proto) {
|
||||
this(className, core);
|
||||
this.node = node;
|
||||
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 {
|
||||
int attributes = READONLY | DONTENUM | PERMANENT;
|
||||
|
||||
// create prototype object
|
||||
HopObject proto = new HopObject();
|
||||
proto.setPrototype(getObjectPrototype(scope));
|
||||
HopObject proto = new HopObject("HopObject", core);
|
||||
proto.setPrototype(getObjectPrototype(core.global));
|
||||
|
||||
// install JavaScript methods and properties
|
||||
Method[] methods = HopObject.class.getDeclaredMethods();
|
||||
|
@ -109,54 +105,6 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param c ...
|
||||
* @param n ...
|
||||
*/
|
||||
public void init(RhinoCore c, INode n) {
|
||||
core = c;
|
||||
node = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 instanceof helma.objectmodel.db.Node) {
|
||||
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
|
||||
|
@ -425,7 +362,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
|
||||
if (id instanceof Number) {
|
||||
n = node.getSubnodeAt(((Number) id).intValue());
|
||||
} else if (id != null) {
|
||||
} else {
|
||||
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;
|
||||
n.loadNodes();
|
||||
List subnodes = n.getSubnodeList();
|
||||
SubnodeList subnodes = n.getSubnodeList();
|
||||
if (subnodes == null) {
|
||||
throw new RuntimeException (
|
||||
"getOrderedView only callable on already existing subnode-collections");
|
||||
}
|
||||
if (subnodes instanceof OrderedSubnodeList) {
|
||||
return new ListViewWrapper ((((OrderedSubnodeList) subnodes).getOrderedView(expr)),
|
||||
return new ListViewWrapper (subnodes.getOrderedView(expr),
|
||||
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;
|
||||
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.");
|
||||
|
@ -55,13 +75,20 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
|||
this.wnm = wnm;
|
||||
this.hObj = hObj;
|
||||
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;
|
||||
|
||||
Method[] methods = this.getClass().getDeclaredMethods();
|
||||
Method[] methods = getClass().getDeclaredMethods();
|
||||
for (int i=0; i<methods.length; i++) {
|
||||
String methodName = methods[i].getName();
|
||||
|
||||
|
@ -70,7 +97,6 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
|||
FunctionObject func = new FunctionObject(methodName,
|
||||
methods[i], this);
|
||||
this.defineProperty(methodName, func, attributes);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,9 +124,7 @@ public class ListViewWrapper extends ScriptableObject implements Wrapper, Script
|
|||
|
||||
// return HopObject in case of a NodeHandle
|
||||
if (obj instanceof NodeHandle) {
|
||||
HopObject hObj = new HopObject();
|
||||
hObj.init(core, ((NodeHandle) obj).getNode(wnm));
|
||||
return hObj;
|
||||
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. ==)
|
||||
|
|
|
@ -113,7 +113,7 @@ public final class RhinoCore implements ScopeProvider {
|
|||
|
||||
pathProto = new PathWrapper(this);
|
||||
|
||||
hopObjectProto = HopObject.init(global);
|
||||
hopObjectProto = HopObject.init(this);
|
||||
// use lazy loaded constructors for all extension objects that
|
||||
// adhere to the ScriptableObject.defineClass() protocol
|
||||
new LazilyLoadedCtor(global, "File",
|
||||
|
@ -207,10 +207,9 @@ public final class RhinoCore implements ScopeProvider {
|
|||
} else if ("hopobject".equals(lowerCaseName)) {
|
||||
op = hopObjectProto;
|
||||
} else {
|
||||
op = new HopObject(name);
|
||||
op.setParentScope(global);
|
||||
op = new HopObject(name, this);
|
||||
}
|
||||
type = registerPrototype(prototype, op);
|
||||
registerPrototype(prototype, op);
|
||||
}
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
|
@ -218,13 +217,10 @@ public final class RhinoCore implements ScopeProvider {
|
|||
// the actual (scripted) constructor on it.
|
||||
if (!"global".equals(lowerCaseName)) {
|
||||
try {
|
||||
FunctionObject fo = new FunctionObject(name, HopObject.hopObjCtor, global);
|
||||
fo.addAsConstructor(global, op);
|
||||
// add static getById() function
|
||||
fo.defineProperty("getById", new GetById(name), GetById.ATTRIBUTES);
|
||||
} catch (Exception ignore) {
|
||||
System.err.println("Error adding ctor for " + name + ": " + ignore);
|
||||
ignore.printStackTrace();
|
||||
new HopObjectCtor(name, this, op);
|
||||
op.setParentScope(global);
|
||||
} catch (Exception x) {
|
||||
app.logError("Error adding ctor for " + name, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,58 +290,52 @@ public final class RhinoCore implements ScopeProvider {
|
|||
* here is to check for update those prototypes which already have been compiled
|
||||
* 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if ((System.currentTimeMillis() - lastUpdate) < 1000L + updateSnooze) {
|
||||
return;
|
||||
// init prototypes and/or update prototype checksums
|
||||
app.typemgr.checkPrototypes();
|
||||
|
||||
// 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
|
||||
app.typemgr.checkPrototypes();
|
||||
type = (TypeInfo) prototypes.get(proto.getLowerCaseName());
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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.init(this, n);
|
||||
esn = new HopObject(protoname, this, n, op);
|
||||
|
||||
wrappercache.put(n, esn);
|
||||
}
|
||||
|
@ -1077,41 +1066,7 @@ public final class RhinoCore implements ScopeProvider {
|
|||
} else {
|
||||
df = new DecimalFormat("#,##0.00");
|
||||
}
|
||||
return df.format(ScriptRuntime.toNumber(thisObj)).toString();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return df.format(ScriptRuntime.toNumber(thisObj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue