191 lines
5.2 KiB
Java
191 lines
5.2 KiB
Java
/*
|
|
* 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.objectmodel.db;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.io.Serializable;
|
|
|
|
/**
|
|
* Container implementation for subnode collections.
|
|
*/
|
|
public class SubnodeList implements Serializable {
|
|
|
|
private static final long serialVersionUID = 711208015232333566L;
|
|
|
|
protected Node node;
|
|
protected List list;
|
|
|
|
transient protected long lastSubnodeFetch = 0;
|
|
transient protected long lastSubnodeChange = 0;
|
|
|
|
|
|
/**
|
|
* Hide/disable zero argument constructor for subclasses
|
|
*/
|
|
private SubnodeList() {}
|
|
|
|
/**
|
|
* Creates a new subnode list
|
|
* @param node the node we belong to
|
|
*/
|
|
public SubnodeList(Node node) {
|
|
this.node = node;
|
|
this.list = new ArrayList();
|
|
}
|
|
|
|
/**
|
|
* Adds the specified object to this list performing
|
|
* custom ordering
|
|
*
|
|
* @param handle element to be inserted.
|
|
*/
|
|
public boolean add(NodeHandle handle) {
|
|
return list.add(handle);
|
|
}
|
|
/**
|
|
* Adds the specified object to the list at the given position
|
|
* @param idx the index to insert the element at
|
|
* @param handle the object to add
|
|
*/
|
|
public void add(int idx, NodeHandle handle) {
|
|
list.add(idx, handle);
|
|
}
|
|
|
|
public NodeHandle get(int index) {
|
|
if (index < 0 || index >= list.size()) {
|
|
return null;
|
|
}
|
|
return (NodeHandle) list.get(index);
|
|
}
|
|
|
|
public Node getNode(int index) {
|
|
Node retval = null;
|
|
NodeHandle handle = get(index);
|
|
|
|
if (handle != null) {
|
|
retval = handle.getNode(node.nmgr);
|
|
// Legacy alarm!
|
|
if ((retval != null) && (retval.parentHandle == null) &&
|
|
!node.nmgr.isRootNode(retval)) {
|
|
retval.setParent(node);
|
|
retval.anonymous = true;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
public boolean contains(Object object) {
|
|
return list.contains(object);
|
|
}
|
|
|
|
public int indexOf(Object object) {
|
|
return list.indexOf(object);
|
|
}
|
|
|
|
/**
|
|
* remove the object specified by the given index-position
|
|
* @param idx the index-position of the NodeHandle to remove
|
|
*/
|
|
public Object remove (int idx) {
|
|
return list.remove(idx);
|
|
}
|
|
|
|
/**
|
|
* remove the given Object from this List
|
|
* @param obj the NodeHandle to remove
|
|
*/
|
|
public boolean remove (Object obj) {
|
|
return list.remove(obj);
|
|
}
|
|
|
|
public Object[] toArray() {
|
|
return list.toArray();
|
|
}
|
|
|
|
/**
|
|
* Return the size of the list.
|
|
* @return the list size
|
|
*/
|
|
public int size() {
|
|
return list.size();
|
|
}
|
|
|
|
protected void update() {
|
|
// also reload if the type mapping has changed.
|
|
long lastChange = getLastSubnodeChange();
|
|
if (lastChange != lastSubnodeFetch) {
|
|
Relation rel = getSubnodeRelation();
|
|
if (rel != null && rel.aggressiveLoading && rel.groupby == null) {
|
|
list = node.nmgr.getNodes(node, rel);
|
|
} else {
|
|
list = node.nmgr.getNodeIDs(node, rel);
|
|
}
|
|
lastSubnodeFetch = lastChange;
|
|
}
|
|
}
|
|
|
|
protected void prefetch(int start, int length) {
|
|
if (start < 0 || start >= size()) {
|
|
return;
|
|
}
|
|
length = (length < 0) ?
|
|
size() - start : Math.min(length, size() - start);
|
|
if (length < 0) {
|
|
return;
|
|
}
|
|
|
|
DbMapping dbmap = getSubnodeMapping();
|
|
|
|
if (dbmap.isRelational()) {
|
|
Relation rel = getSubnodeRelation();
|
|
node.nmgr.prefetchNodes(node, rel, this, start, length);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compute a serial number indicating the last change in subnode collection
|
|
* @return a serial number that increases with each subnode change
|
|
*/
|
|
protected long getLastSubnodeChange() {
|
|
// include dbmap.getLastTypeChange to also reload if the type mapping has changed.
|
|
long checkSum = lastSubnodeChange + node.dbmap.getLastTypeChange();
|
|
Relation rel = getSubnodeRelation();
|
|
return rel == null || rel.aggressiveCaching ?
|
|
checkSum : checkSum + rel.otherType.getLastDataChange();
|
|
}
|
|
|
|
protected synchronized void markAsChanged() {
|
|
lastSubnodeChange += 1;
|
|
}
|
|
|
|
protected boolean hasRelationalNodes() {
|
|
DbMapping dbmap = getSubnodeMapping();
|
|
return (dbmap != null && dbmap.isRelational()
|
|
&& ((node.getState() != Node.TRANSIENT && node.getState() != Node.NEW)
|
|
|| node.getSubnodeRelation() != null));
|
|
}
|
|
|
|
protected DbMapping getSubnodeMapping() {
|
|
return node.dbmap == null ? null : node.dbmap.getSubnodeMapping();
|
|
}
|
|
|
|
protected Relation getSubnodeRelation() {
|
|
return node.dbmap == null ? null : node.dbmap.getSubnodeRelation();
|
|
}
|
|
}
|