helma/src/main/java/helma/objectmodel/db/SubnodeList.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();
}
}