You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2007/05/29 17:51:31 UTC
svn commit: r542571 [1/2] - in
/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi:
./ hierarchy/ nodetype/ operation/ state/ version/ xml/
Author: angela
Date: Tue May 29 08:51:30 2007
New Revision: 542571
URL: http://svn.apache.org/viewvc?view=rev&rev=542571
Log:
improve memory consumption of the current hierarchy implementation
Added:
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java (with props)
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java (with props)
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java (with props)
Modified:
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryFactory.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntryImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/nodetype/NodeTypeRegistryImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/AddLabel.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/Move.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/RemoveLabel.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/operation/SetMixin.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ItemState.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/NodeState.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/PropertyState.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/SessionImporter.java
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/NodeImpl.java Tue May 29 08:51:30 2007
@@ -31,7 +31,6 @@
import org.apache.jackrabbit.jcr2spi.state.ItemStateValidator;
import org.apache.jackrabbit.jcr2spi.state.NodeReferences;
import org.apache.jackrabbit.jcr2spi.state.Status;
-import org.apache.jackrabbit.jcr2spi.state.PropertyState;
import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeManagerImpl;
import org.apache.jackrabbit.jcr2spi.nodetype.EffectiveNodeType;
import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeConflictException;
@@ -709,30 +708,35 @@
}
/**
- * Retrieves all mixins currently present on this node including those,
- * that have been transiently added and excluding those, that have been
- * transiently removed.<br>
+ * Retrieves the value of the jcr:mixinTypes property present with this
+ * Node including those that have been transiently added and excluding
+ * those, that have been transiently removed.<br>
* NOTE, that the result of this method, does NOT represent the list of
- * mixin-types that currently affect this node. Instead if represents the
- * current value of the jcr:mixinTypes property.
- *
+ * mixin-types that currently affect this node.
+ *
* @return
*/
private List getMixinTypes() {
- QName[] mixinValue = new QName[0];
- if (hasProperty(QName.JCR_MIXINTYPES)) {
- if (getNodeState().getStatus() == Status.EXISTING) {
- mixinValue = getNodeState().getMixinTypeNames();
- } else {
- // possibility that a mixin has been transient added
- try {
- PropertyState ps = getNodeState().getPropertyState(QName.JCR_MIXINTYPES);
- mixinValue = StateUtility.getMixinNames(ps);
- } catch (RepositoryException e) {
- // should never occur
- log.error("Internal error", e);
+ QName[] mixinValue;
+ if (getNodeState().getStatus() == Status.EXISTING) {
+ // jcr:mixinTypes must correspond to the mixins present on the nodestate.
+ mixinValue = getNodeState().getMixinTypeNames();
+ } else {
+ try {
+ PropertyEntry pe = getNodeEntry().getPropertyEntry(QName.JCR_MIXINTYPES);
+ if (pe != null) {
+ // prop entry exists (and ev. has been transiently mod.)
+ // -> retrieve mixin types from prop
+ mixinValue = StateUtility.getMixinNames(pe.getPropertyState());
+ } else {
+ // prop entry has not been loaded yet -> not modified
+ mixinValue = getNodeState().getMixinTypeNames();
}
- } // else: no mixins present
+ } catch (RepositoryException e) {
+ // should never occur
+ log.warn("Internal error", e);
+ mixinValue = new QName[0];
+ }
}
List l = new ArrayList();
l.addAll(Arrays.asList(mixinValue));
@@ -1343,7 +1347,7 @@
protected Property getProperty(QName qName) throws PathNotFoundException, RepositoryException {
checkStatus();
try {
- PropertyEntry pEntry = getNodeEntry().getPropertyEntry(qName);
+ PropertyEntry pEntry = getNodeEntry().getPropertyEntry(qName, true);
if (pEntry == null) {
throw new PathNotFoundException(qName.toString());
}
@@ -1589,11 +1593,11 @@
} else if (pe == Path.PARENT_ELEMENT) {
targetEntry = getNodeEntry().getParent();
} else {
- targetEntry = getNodeEntry().getNodeEntry(pe.getName(), pe.getNormalizedIndex());
+ // try to get child entry + force loading of not known yet
+ targetEntry = getNodeEntry().getNodeEntry(pe.getName(), pe.getNormalizedIndex(), true);
}
- }
- if (targetEntry == null) {
- // rp length > 1 OR child entry has not yet been loaded.
+ } else {
+ // rp length > 1
Path p = getQPath(rp);
HierarchyEntry entry = session.getHierarchyManager().getHierarchyEntry(p.getCanonicalPath());
if (entry.denotesNode()) {
@@ -1626,17 +1630,14 @@
PropertyEntry targetEntry = null;
try {
Path rp = PathFormat.parse(relPath, session.getNamespaceResolver());
- if (rp.getLength() == 1) {
+ if (rp.getLength() == 1 && rp.getNameElement().denotesName()) {
// a single path element must always denote a name. '.' and '..'
- // will never point to a property.
- if (rp.getNameElement().denotesName()) {
- QName propName = rp.getNameElement().getName();
- // check if property entry exists
- targetEntry = getNodeEntry().getPropertyEntry(propName);
- } // else: entry may not have been loaded yet -> try via H-Mgr
- }
-
- if (targetEntry == null) {
+ // will never point to a property. If the NodeEntry does not
+ // contain such a pe, the targetEntry is 'null;
+ QName propName = rp.getNameElement().getName();
+ // check if property entry exists
+ targetEntry = getNodeEntry().getPropertyEntry(propName, true);
+ } else {
// build and resolve absolute path
Path p = getQPath(rp).getCanonicalPath();
try {
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntries.java Tue May 29 08:51:30 2007
@@ -16,258 +16,88 @@
*/
package org.apache.jackrabbit.jcr2spi.hierarchy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.name.Path;
import org.apache.jackrabbit.spi.ChildInfo;
-import org.apache.commons.collections.list.AbstractLinkedList;
-import org.apache.commons.collections.iterators.UnmodifiableIterator;
+import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import java.util.Collections;
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
+import java.util.Iterator;
/**
- * <code>ChildNodeEntries</code> represents an insertion-ordered collection of
- * <code>NodeEntry</code>s that also maintains the index values of same-name
- * siblings on insertion and removal.
- * <p/>
- * <code>ChildNodeEntries</code> also provides an unmodifiable
- * <code>Collection</code> view.
+ * <code>ChildNodeEntries</code> represents a collection of <code>NodeEntry</code>s that
+ * also maintains the index values of same-name siblings on insertion and removal.
*/
-final class ChildNodeEntries implements Collection {
-
- private static Logger log = LoggerFactory.getLogger(ChildNodeEntries.class);
+public interface ChildNodeEntries {
static final int STATUS_OK = 0;
static final int STATUS_INVALIDATED = 1;
- private final NodeEntryImpl parent;
- private int status = STATUS_OK;
-
- /**
- * Linked list of {@link NodeEntry} instances.
- */
- private final ChildNodeEntries.LinkedEntries entries = new LinkedEntries();
-
/**
- * map used for lookup by name
- * (key=name, value=either a single {@link AbstractLinkedList.Node} or a
- * list of {@link AbstractLinkedList.Node}s which are sns entries)
- */
- private final Map nameMap = new HashMap();
-
- /**
- * Create <code>ChildNodeEntries</code> for the given node state.
+ * Returns the status of this ChildNodeEntries object.
*
- * @param parent
+ * @return {@link #STATUS_OK} or {@link #STATUS_INVALIDATED}
*/
- ChildNodeEntries(NodeEntryImpl parent) {
- this.parent = parent;
- }
+ int getStatus();
/**
- * Mark <code>ChildNodeEntries</code> in order to force
- */
- void setStatus(int status) {
- if (status == STATUS_INVALIDATED || status == STATUS_OK) {
- this.status = status;
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- int getStatus() {
- return status;
- }
-
- /**
- * Returns true, if this ChildNodeEntries contains a entry that matches
- * the given name and either index or uniqueID:<br>
- * If <code>uniqueID</code> is not <code>null</code> the given index is
- * ignored since it is not required to identify a child node entry.
- * Otherwise the given index is used.
+ * Mark <code>ChildNodeEntries</code> in order to force reloading the
+ * entries.
*
- * @param name
- * @param index
- * @param uniqueID
- * @return
+ * @param status
*/
- boolean contains(QName name, int index, String uniqueID) {
- if (uniqueID == null) {
- return contains(name, index);
- } else {
- return contains(name, uniqueID);
- }
- }
+ void setStatus(int status);
/**
+ * Reloads this <code>ChildNodeEntries</code> object.
*
- * @param name
- * @param index
- * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
*/
- private boolean contains(QName name, int index) {
- if (!nameMap.containsKey(name) || index < Path.INDEX_DEFAULT) {
- // no matching child node entry
- return false;
- }
- Object o = nameMap.get(name);
- if (o instanceof List) {
- // SNS
- int listIndex = index - 1;
- return listIndex < ((List) o).size();
- } else {
- // single child node with this name -> matches only if request
- // index equals the default-index
- return index == Path.INDEX_DEFAULT;
- }
- }
-
+ void reload() throws ItemNotFoundException, RepositoryException;
+
/**
+ * Returns an unmodifiable iterator over all NodeEntry objects present in
+ * this ChildNodeEntries collection irrespective of their status.
*
- * @param name
- * @param uniqueID
- * @return
+ * @return Iterator over all NodeEntry object
*/
- private boolean contains(QName name, String uniqueID) {
- if (uniqueID == null) {
- throw new IllegalArgumentException();
- }
- if (!nameMap.containsKey(name)) {
- // no matching child node entry
- return false;
- }
- Object o = nameMap.get(name);
- if (o instanceof List) {
- // SNS
- for (Iterator it = ((List) o).iterator(); it.hasNext(); ) {
- ChildNodeEntries.LinkedEntries.LinkNode n = (LinkedEntries.LinkNode) it.next();
- NodeEntry cne = n.getNodeEntry();
- if (uniqueID.equals(cne.getUniqueID())) {
- return true;
- }
- }
- } else {
- // single child node with this name
- NodeEntry cne = ((ChildNodeEntries.LinkedEntries.LinkNode) o).getNodeEntry();
- return uniqueID.equals(cne.getUniqueID());
- }
- // no matching entry found
- return false;
- }
+ Iterator iterator();
/**
* Returns a <code>List</code> of <code>NodeEntry</code>s for the
* given <code>nodeName</code>. This method does <b>not</b> filter out
- * removed <code>NodeEntry</code>s!
+ * removed <code>NodeEntry</code>s.
*
* @param nodeName the child node name.
* @return same name sibling nodes with the given <code>nodeName</code>.
*/
- List get(QName nodeName) {
- Object obj = nameMap.get(nodeName);
- if (obj == null) {
- return Collections.EMPTY_LIST;
- }
- if (obj instanceof List) {
- final List sns = (List) obj;
- // map entry is a list of siblings
- return Collections.unmodifiableList(new AbstractList() {
-
- public Object get(int index) {
- return ((LinkedEntries.LinkNode) sns.get(index)).getNodeEntry();
- }
-
- public int size() {
- return sns.size();
- }
-
- public Iterator iterator() {
- return new Iterator() {
-
- private Iterator iter = sns.iterator();
-
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
-
- public boolean hasNext() {
- return iter.hasNext();
- }
-
- public Object next() {
- return ((LinkedEntries.LinkNode) iter.next()).getNodeEntry();
- }
- };
- }
- });
- } else {
- // map entry is a single child node entry
- return Collections.singletonList(((LinkedEntries.LinkNode) obj).getNodeEntry());
- }
- }
+ List get(QName nodeName);
/**
* Returns the <code>NodeEntry</code> with the given
- * <code>nodeName</code> and <code>index</code>. This method ignores
- * <code>NodeEntry</code>s which are marked removed!
+ * <code>nodeName</code> and <code>index</code>. Note, that this method
+ * does <b>not</b> filter out removed <code>NodeEntry</code>s.
*
* @param nodeName name of the child node entry.
* @param index the index of the child node entry.
* @return the <code>NodeEntry</code> or <code>null</code> if there
- * is no such <code>NodeEntry</code>.
+ * is no such <code>NodeEntry</code>.
*/
- NodeEntry get(QName nodeName, int index) {
- if (index < Path.INDEX_DEFAULT) {
- throw new IllegalArgumentException("index is 1-based");
- }
- Object obj = nameMap.get(nodeName);
- if (obj == null) {
- return null;
- }
- if (obj instanceof List) {
- // map entry is a list of siblings
- List siblings = (List) obj;
- return findMatchingEntry(siblings, index, true);
- } else {
- // map entry is a single child node entry
- if (index == Path.INDEX_DEFAULT) {
- return ((LinkedEntries.LinkNode) obj).getNodeEntry();
- }
- }
- return null;
- }
+ NodeEntry get(QName nodeName, int index);
/**
+ * Return the <code>NodeEntry</code> that matches the given nodeName and
+ * uniqueID or <code>null</code> if no matching entry can be found.
*
* @param nodeName
* @param uniqueID
* @return
* @throws IllegalArgumentException if the given uniqueID is null.
*/
- NodeEntry get(QName nodeName, String uniqueID) {
- if (uniqueID == null) {
- throw new IllegalArgumentException();
- }
- Iterator cneIter = (nodeName != null) ? get(nodeName).iterator() : entries.iterator();
- while (cneIter.hasNext()) {
- NodeEntry cne = (NodeEntry) cneIter.next();
- if (uniqueID.equals(cne.getUniqueID())) {
- return cne;
- }
- }
- return null;
- }
+ NodeEntry get(QName nodeName, String uniqueID);
/**
* Find the matching NodeEntry for the given <code>ChildInfo</code>. Returns
@@ -277,61 +107,7 @@
* @param childInfo
* @return
*/
- NodeEntry get(ChildInfo childInfo) {
- String uniqueID = childInfo.getUniqueID();
- if (uniqueID != null) {
- return get(childInfo.getName(), uniqueID);
- } else {
- int index = childInfo.getIndex();
- Object obj = nameMap.get(childInfo.getName());
- if (obj == null) {
- return null;
- } else if (obj instanceof List) {
- // map entry is a list of siblings
- List siblings = (List) obj;
- return findMatchingEntry(siblings, index, false);
- } else if (index == Path.INDEX_DEFAULT) {
- // map entry is a single child node entry
- return ((LinkedEntries.LinkNode) obj).getNodeEntry();
- } // else return 'null'
- }
- return null;
- }
-
- private static NodeEntry findMatchingEntry(List siblings, int index, boolean checkValidity) {
- // shortcut if index can never match
- if (index > siblings.size()) {
- return null;
- }
- if (!checkValidity) {
- return ((LinkedEntries.LinkNode) siblings.get(index - 1)).getNodeEntry();
- } else {
- // filter out removed states
- for (Iterator it = siblings.iterator(); it.hasNext(); ) {
- NodeEntry cne = ((LinkedEntries.LinkNode) it.next()).getNodeEntry();
- if (cne.isAvailable()) {
- try {
- if (cne.getNodeState().isValid()) {
- index--;
- } else {
- // child node removed
- }
- } catch (RepositoryException e) {
- // ignore for index detection. entry does not exist or is
- // not accessible
- }
- } else {
- // then this child node entry has never been accessed
- // before and is assumed valid // TODO: check if correct.
- index--;
- }
- if (index == 0) {
- return cne;
- }
- }
- }
- return null;
- }
+ NodeEntry get(ChildInfo childInfo);
/**
* Adds a <code>NodeEntry</code> to the end of the list. Same as
@@ -339,9 +115,7 @@
*
* @param cne the <code>NodeEntry</code> to add.
*/
- void add(NodeEntry cne) {
- add(cne, Path.INDEX_UNDEFINED);
- }
+ void add(NodeEntry cne);
/**
* Adds a <code>NodeEntry</code>.<br>
@@ -355,134 +129,15 @@
*
* @param cne the <code>NodeEntry</code> to add.
*/
- void add(NodeEntry cne, int index) {
- QName nodeName = cne.getQName();
+ void add(NodeEntry cne, int index);
- // retrieve ev. sibling node with same index if index is 'undefined'
- // the existing entry is always null and no reordering occur.
- LinkedEntries.LinkNode existing = (index < Path.INDEX_DEFAULT) ? null : getLinkNode(nodeName, index);
-
- // in case index greater than default -> make sure all intermediate
- // entries exist.
- if (index > Path.INDEX_DEFAULT) {
- int previousIndex = index - 1;
- LinkedEntries.LinkNode previous = getLinkNode(nodeName, previousIndex);
- if (previous == null) {
- // add missing entry (or entries)
- try {
- parent.addNodeEntry(nodeName, null, previousIndex);
- } catch (RepositoryException e) {
- // should never occur
- log.debug("Internal error", e.getMessage());
- }
-
- } // else: all intermediate entries exist
- } // else: undefined or default index are not affected
-
- // add new entry (same as #add(NodeEntry)
- List siblings = null;
- Object obj = nameMap.get(nodeName);
- if (obj != null) {
- if (obj instanceof List) {
- // map entry is a list of siblings
- siblings = (ArrayList) obj;
- } else {
- // map entry is a single child node entry,
- // convert to siblings list
- siblings = new ArrayList();
- siblings.add(obj);
- nameMap.put(nodeName, siblings);
- }
- }
-
- LinkedEntries.LinkNode ln = entries.add(cne);
- if (siblings != null) {
- siblings.add(ln);
- } else {
- nameMap.put(nodeName, ln);
- }
-
- // reorder the child entries if, the new entry must be inserted rather
- // than appended at the end of the list.
- if (existing != null) {
- reorder(obj, ln, existing);
- }
- }
-
- void add(NodeEntry entry, NodeEntry beforeEntry) {
- if (beforeEntry != null) {
- // the link node where the new entry is ordered before
- LinkedEntries.LinkNode beforeLN = getLinkNode(beforeEntry);
- if (beforeLN == null) {
- throw new NoSuchElementException();
- }
- add(entry);
- Object insertObj = nameMap.get(entry.getQName());
- LinkedEntries.LinkNode insertLN = getLinkNode(entry);
- reorder(insertObj, insertLN, beforeLN);
- } else {
- // 'before' is null -> simply append new entry at the end
- add(entry);
- }
- }
-
- /**
- * Removes the child node entry with the given <code>nodeName</code> and
- * <code>index</code>.
- *
- * @param nodeName the name of the child node entry to remove.
- * @param index the index of the child node entry to remove.
- * @return the removed <code>NodeEntry</code> or <code>null</code>
- * if there is no matching <code>NodeEntry</code>.
- */
- NodeEntry remove(QName nodeName, int index) {
- if (index < Path.INDEX_DEFAULT) {
- throw new IllegalArgumentException("index is 1-based");
- }
-
- Object obj = nameMap.get(nodeName);
- if (obj == null) {
- return null;
- }
-
- if (obj instanceof LinkedEntries.LinkNode) {
- // map entry is a single child node entry
- if (index != Path.INDEX_DEFAULT) {
- return null;
- }
- LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) obj;
- nameMap.remove(nodeName);
- // remove LinkNode from entries
- ln.remove();
- return ln.getNodeEntry();
- }
-
- // map entry is a list of siblings
- List siblings = (List) obj;
- if (index > siblings.size()) {
- return null;
- }
-
- // remove from siblings list
- LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) siblings.remove(index - 1);
- NodeEntry removedEntry = ln.getNodeEntry();
- // remove from ordered entries
- ln.remove();
-
- // clean up name lookup map if necessary
- if (siblings.size() == 0) {
- // no more entries with that name left:
- // remove from name lookup map as well
- nameMap.remove(nodeName);
- } else if (siblings.size() == 1) {
- // just one entry with that name left:
- // discard siblings list and update name lookup map accordingly
- nameMap.put(nodeName, siblings.get(0));
- }
-
- // we're done
- return removedEntry;
- }
+ /**
+ * Adds a the new <code>NodeEntry</code> before <code>beforeEntry</code>.
+ *
+ * @param entry
+ * @param beforeEntry
+ */
+ void add(NodeEntry entry, NodeEntry beforeEntry);
/**
* Removes the child node entry refering to the node state.
@@ -490,432 +145,21 @@
* @param childEntry the entry to be removed.
* @return the removed entry or <code>null</code> if there is no such entry.
*/
- NodeEntry remove(NodeEntry childEntry) {
- List l = get(childEntry.getQName());
- for (int i = 0; i < l.size(); i++) {
- NodeEntry tmp = (NodeEntry) l.get(i);
- if (tmp == childEntry) {
- int index = i+1; // index is 1-based
- return remove(childEntry.getQName(), index);
- }
- }
- return null;
- }
-
- /**
- * Reorders an existing <code>NodeState</code> before another
- * <code>NodeState</code>. If <code>beforeNode</code> is
- * <code>null</code> <code>insertNode</code> is moved to the end of the
+ NodeEntry remove(NodeEntry childEntry);
+
+ /**
+ * Reorders an existing <code>NodeEntry</code> before another
+ * <code>NodeEntry</code>. If <code>beforeEntry</code> is
+ * <code>null</code> <code>insertEntry</code> is moved to the end of the
* child node entries.
*
- * @param insertNode the NodeEntry to move.
- * @param beforeNode the NodeEntry where <code>insertNode</code> is
+ * @param insertEntry the NodeEntry to move.
+ * @param beforeEntry the NodeEntry where <code>insertEntry</code> is
* reordered to.
- * @return the NodeEntry that followed the 'insertNode' before the reordering.
- * @throws NoSuchElementException if <code>insertNode</code> or
- * <code>beforeNode</code> does not have a <code>NodeEntry</code>
+ * @return the NodeEntry that followed the 'insertEntry' before the reordering.
+ * @throws NoSuchElementException if <code>insertEntry</code> or
+ * <code>beforeEntry</code> does not have a <code>NodeEntry</code>
* in this <code>ChildNodeEntries</code>.
*/
- NodeEntry reorder(NodeEntry insertNode, NodeEntry beforeNode) {
- Object insertObj = nameMap.get(insertNode.getQName());
- // the link node to move
- LinkedEntries.LinkNode insertLN = getLinkNode(insertNode);
- if (insertLN == null) {
- throw new NoSuchElementException();
- }
- // the link node where insertLN is ordered before
- LinkedEntries.LinkNode beforeLN = (beforeNode != null) ? getLinkNode(beforeNode) : null;
- if (beforeNode != null && beforeLN == null) {
- throw new NoSuchElementException();
- }
-
- NodeEntry previousBefore = insertLN.getNextLinkNode().getNodeEntry();
- if (previousBefore != beforeNode) {
- reorder(insertObj, insertLN, beforeLN);
- }
- return previousBefore;
- }
-
- /**
- *
- * @param insertObj
- * @param insertLN
- * @param beforeLN
- */
- private void reorder(Object insertObj, LinkedEntries.LinkNode insertLN, LinkedEntries.LinkNode beforeLN) {
- if (insertObj instanceof List) {
- // adapt name lookup lists
- List insertList = (List) insertObj;
- if (beforeLN == null) {
- // simply move to end of list
- insertList.remove(insertLN);
- insertList.add(insertLN);
- } else {
- // move based on position of beforeLN
- // count our same name siblings until we reach beforeLN
- int snsCount = 0;
- QName insertName = insertLN.getNodeEntry().getQName();
- for (Iterator it = entries.linkNodeIterator(); it.hasNext(); ) {
- LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
- if (ln == beforeLN) {
- insertList.remove(insertLN);
- insertList.add(snsCount, insertLN);
- break;
- } else if (ln == insertLN) {
- // do not increment snsCount for node to reorder
- } else if (ln.getNodeEntry().getQName().equals(insertName)) {
- snsCount++;
- }
- }
- }
- } // else: no same name siblings -> no special handling required
-
- // reorder in linked list
- entries.reorderNode(insertLN, beforeLN);
- }
-
- /**
- * Returns the matching <code>LinkNode</code> from a list or a single
- * <code>LinkNode</code>. This method will return <code>null</code>
- * if none of the entries matches either due to missing entry for given
- * state name or due to missing availability of the <code>NodeEntry</code>.
- *
- * @param nodeEntry the <code>NodeEntry</code> that is compared to the
- * resolution of any <code>NodeEntry</code> that matches by name.
- * @return the matching <code>LinkNode</code> or <code>null</code>
- */
- private LinkedEntries.LinkNode getLinkNode(NodeEntry nodeEntry) {
- Object listOrLinkNode = nameMap.get(nodeEntry.getQName());
- if (listOrLinkNode == null) {
- // no matching child node entry
- return null;
- }
-
- if (listOrLinkNode instanceof List) {
- // has same name sibling
- for (Iterator it = ((List) listOrLinkNode).iterator(); it.hasNext();) {
- LinkedEntries.LinkNode n = (LinkedEntries.LinkNode) it.next();
- NodeEntry cne = n.getNodeEntry();
- if (cne == nodeEntry) {
- return n;
- }
- }
- } else {
- // single child node with this name
- NodeEntry cne = ((LinkedEntries.LinkNode) listOrLinkNode).getNodeEntry();
- if (cne == nodeEntry) {
- return (LinkedEntries.LinkNode) listOrLinkNode;
- }
- }
- // not found
- return null;
- }
-
- /**
- * Returns the matching <code>LinkNode</code> from a list or a single
- * <code>LinkNode</code>. This method will return <code>null</code>
- * if none of the entries matches.
- *
- * @param name
- * @param index
- * @return the matching <code>LinkNode</code> or <code>null</code>.
- */
- private LinkedEntries.LinkNode getLinkNode(QName name, int index) {
- Object listOrLinkNode = nameMap.get(name);
- if (listOrLinkNode == null) {
- // no matching child node entry
- return null;
- }
-
- if (listOrLinkNode instanceof List) {
- // has same name sibling -> check if list size matches
- int listIndex = index - 1;
- List lnList = (List) listOrLinkNode;
- if (listIndex < lnList.size()) {
- return (LinkedEntries.LinkNode) lnList.get(listIndex);
- }
- } else if (index == Path.INDEX_DEFAULT) {
- // single child node with this name -> matches is requested index
- // equals to the default index.
- return (LinkedEntries.LinkNode) listOrLinkNode;
- }
-
- // no matching entry
- return null;
- }
- //--------------------------------------------< unmodifiable Collection >---
- /**
- * @see Collection#contains(Object)
- */
- public boolean contains(Object o) {
- if (o instanceof NodeEntry) {
- // narrow down to same name sibling nodes and check list
- return get(((NodeEntry) o).getQName()).contains(o);
- } else {
- return false;
- }
- }
-
- /**
- * @see Collection#containsAll(Collection)
- */
- public boolean containsAll(Collection c) {
- Iterator iter = c.iterator();
- while (iter.hasNext()) {
- if (!contains(iter.next())) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * @see Collection#isEmpty()
- */
- public boolean isEmpty() {
- return entries.isEmpty();
- }
-
- /**
- * @see Collection#iterator()
- */
- public Iterator iterator() {
- return UnmodifiableIterator.decorate(entries.iterator());
- }
-
- /**
- * @see Collection#size()
- */
- public int size() {
- return entries.size();
- }
-
- /**
- * @see Collection#toArray()
- */
- public Object[] toArray() {
- NodeEntry[] array = new NodeEntry[size()];
- return toArray(array);
- }
-
- /**
- * @see Collection#toArray(Object[])
- */
- public Object[] toArray(Object[] a) {
- if (!a.getClass().getComponentType().isAssignableFrom(NodeEntry.class)) {
- throw new ArrayStoreException();
- }
- if (a.length < size()) {
- a = new NodeEntry[size()];
- }
- Iterator iter = entries.iterator();
- int i = 0;
- while (iter.hasNext()) {
- a[i++] = iter.next();
- }
- while (i < a.length) {
- a[i++] = null;
- }
- return a;
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#add(Object)
- */
- public boolean add(Object o) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#addAll(Collection)
- */
- public boolean addAll(Collection c) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#clear()
- */
- public void clear() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#remove(Object)
- */
- public boolean remove(Object o) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#removeAll(Collection)
- */
- public boolean removeAll(Collection c) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Throws <code>UnsupportedOperationException</code>.
- *
- * @see Collection#retainAll(Collection)
- */
- public boolean retainAll(Collection c) {
- throw new UnsupportedOperationException();
- }
-
- //-------------------------------------------------< AbstractLinkedList >---
- /**
- * An implementation of a linked list which provides access to the internal
- * LinkNode which links the entries of the list.
- */
- private static final class LinkedEntries extends AbstractLinkedList {
-
- LinkedEntries() {
- super();
- init();
- }
-
- /**
- * Adds a child node entry to this list.
- *
- * @param cne the child node entry to add.
- * @return the LinkNode which refers to the added <code>NodeEntry</code>.
- */
- LinkedEntries.LinkNode add(NodeEntry cne) {
- LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) createNode(cne);
- addNode(ln, header);
- return ln;
- }
-
- /**
- * Reorders an existing <code>LinkNode</code> before another existing
- * <code>LinkNode</code>. If <code>before</code> is <code>null</code>
- * the <code>insert</code> node is moved to the end of the list.
- *
- * @param insert the node to reorder.
- * @param before the node where to reorder node <code>insert</code>.
- */
- void reorderNode(LinkedEntries.LinkNode insert, LinkedEntries.LinkNode before) {
- removeNode(insert);
- if (before == null) {
- addNode(insert, header);
- } else {
- addNode(insert, before);
- }
- }
-
- /**
- * Replace the value of the given LinkNode with a new NodeEntry
- * value.
- *
- * @param node
- * @param value
- */
- void replaceNode(LinkedEntries.LinkNode node, NodeEntry value) {
- updateNode(node, value);
- }
-
- /**
- * Create a new <code>LinkNode</code> for a given {@link NodeEntry}
- * <code>value</code>.
- *
- * @param value a child node entry.
- * @return a wrapping {@link org.apache.jackrabbit.jcr2spi.hierarchy.ChildNodeEntries.LinkedEntries.LinkNode}.
- * @see AbstractLinkedList#createNode(Object)
- */
- protected Node createNode(Object value) {
- return new LinkedEntries.LinkNode(value);
- }
-
- /**
- * @return a new <code>LinkNode</code>.
- * @see AbstractLinkedList#createHeaderNode()
- */
- protected Node createHeaderNode() {
- return new LinkedEntries.LinkNode();
- }
-
- /**
- * Returns an iterator over all
- * @return
- */
- Iterator linkNodeIterator() {
- return new Iterator() {
-
- private LinkedEntries.LinkNode next = ((LinkedEntries.LinkNode) header).getNextLinkNode();
-
- private int expectedModCount = modCount;
-
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
-
- public boolean hasNext() {
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- return next != header;
- }
-
- public Object next() {
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- LinkedEntries.LinkNode n = next;
- next = next.getNextLinkNode();
- return n;
- }
- };
- }
-
- //----------------------------------------------------------------------
-
- /**
- * Extends the <code>AbstractLinkedList.Node</code>.
- */
- private final class LinkNode extends Node {
-
- protected LinkNode() {
- super();
- }
-
- protected LinkNode(Object value) {
- super(value);
- }
-
- /**
- * @return the wrapped <code>NodeEntry</code>.
- */
- public NodeEntry getNodeEntry() {
- return (NodeEntry) super.getValue();
- }
-
- /**
- * Removes this <code>LinkNode</code> from the linked list.
- */
- public void remove() {
- removeNode(this);
- }
-
- /**
- * @return the next LinkNode.
- */
- public LinkedEntries.LinkNode getNextLinkNode() {
- return (LinkedEntries.LinkNode) super.getNextNode();
- }
- }
- }
+ NodeEntry reorder(NodeEntry insertEntry, NodeEntry beforeEntry);
}
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java?view=auto&rev=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java Tue May 29 08:51:30 2007
@@ -0,0 +1,745 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jcr2spi.hierarchy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.spi.ChildInfo;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.jcr2spi.state.Status;
+import org.apache.commons.collections.list.AbstractLinkedList;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.ItemNotFoundException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+import java.lang.ref.WeakReference;
+
+/**
+ * <code>ChildNodeEntriesImpl</code> implements a memory sensitive implementation
+ * of the <code>ChildNodeEntries</code> interface.
+ */
+final class ChildNodeEntriesImpl implements ChildNodeEntries {
+
+ private static Logger log = LoggerFactory.getLogger(ChildNodeEntriesImpl.class);
+
+ private int status = STATUS_OK;
+
+ /**
+ * Linked list of {@link NodeEntry} instances.
+ */
+ private final LinkedEntries entries;
+
+ /**
+ * Map used for lookup by name.
+ */
+ private final NameMap entriesByName;
+
+ private final NodeEntry parent;
+ private final EntryFactory factory;
+
+ /**
+ * Create a new <code>ChildNodeEntries</code> collection
+ */
+ ChildNodeEntriesImpl(NodeEntry parent, EntryFactory factory) throws ItemNotFoundException, RepositoryException {
+ entriesByName = new NameMap();
+ entries = new LinkedEntries();
+
+ this.parent = parent;
+ this.factory = factory;
+
+ if (parent.getStatus() == Status.NEW || Status.isTerminal(parent.getStatus())) {
+ return; // cannot retrieve child-entries from persistent layer
+ }
+
+ NodeId id = parent.getWorkspaceId();
+ Iterator it = factory.getItemStateFactory().getChildNodeInfos(id);
+ // simply add all child entries to the empty collection
+ while (it.hasNext()) {
+ ChildInfo ci = (ChildInfo) it.next();
+ NodeEntry entry = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
+ add(entry, ci.getIndex());
+ }
+ }
+
+ /**
+ * @see ChildNodeEntries#getStatus()
+ */
+ public int getStatus() {
+ return status;
+ }
+
+ /**
+ * Mark <code>ChildNodeEntries</code> in order to force reloading the
+ * entries.
+ *
+ * @see ChildNodeEntries#setStatus(int)
+ */
+ public void setStatus(int status) {
+ if (status == STATUS_INVALIDATED || status == STATUS_OK) {
+ this.status = status;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * @see ChildNodeEntries#reload()
+ */
+ public synchronized void reload() throws ItemNotFoundException, RepositoryException {
+ if (status == STATUS_OK ||
+ parent.getStatus() == Status.NEW || Status.isTerminal(parent.getStatus())) {
+ // nothing to do
+ return;
+ }
+
+ NodeId id = parent.getWorkspaceId();
+ Iterator it = factory.getItemStateFactory().getChildNodeInfos(id);
+ // create list from all ChildInfos (for multiple loop)
+ List cInfos = new ArrayList();
+ while (it.hasNext()) {
+ cInfos.add(it.next());
+ }
+ // first make sure the ordering of all existing entries is ok
+ NodeEntry entry = null;
+ for (it = cInfos.iterator(); it.hasNext();) {
+ ChildInfo ci = (ChildInfo) it.next();
+ NodeEntry nextEntry = get(ci);
+ if (nextEntry != null) {
+ if (entry != null) {
+ reorder(entry, nextEntry);
+ }
+ entry = nextEntry;
+ }
+ }
+ // then insert the 'new' entries
+ List newEntries = new ArrayList();
+ for (it = cInfos.iterator(); it.hasNext();) {
+ ChildInfo ci = (ChildInfo) it.next();
+ NodeEntry beforeEntry = get(ci);
+ if (beforeEntry == null) {
+ NodeEntry ne = factory.createNodeEntry(parent, ci.getName(), ci.getUniqueID());
+ newEntries.add(ne);
+ } else {
+ // insert all new entries from the list BEFORE the existing
+ // 'nextEntry'. Then clear the list.
+ for (int i = 0; i < newEntries.size(); i++) {
+ add((NodeEntry) newEntries.get(i), beforeEntry);
+ }
+ newEntries.clear();
+ }
+ }
+ // deal with new entries at the end
+ for (int i = 0; i < newEntries.size(); i++) {
+ add((NodeEntry) newEntries.get(i));
+ }
+ // finally reset the status
+ setStatus(ChildNodeEntries.STATUS_OK);
+ }
+
+ /**
+ * @see ChildNodeEntries#iterator()
+ */
+ public Iterator iterator() {
+ List l = new ArrayList(entries.size());
+ for (Iterator it = entries.linkNodeIterator(); it.hasNext();) {
+ l.add(((LinkedEntries.LinkNode)it.next()).getNodeEntry());
+ }
+ return Collections.unmodifiableList(l).iterator();
+ }
+
+ /**
+ * @see ChildNodeEntries#get(QName)
+ */
+ public List get(QName nodeName) {
+ return entriesByName.getList(nodeName);
+ }
+
+ /**
+ * @see ChildNodeEntries#get(QName, int)
+ */
+ public NodeEntry get(QName nodeName, int index) {
+ if (index < Path.INDEX_DEFAULT) {
+ throw new IllegalArgumentException("index is 1-based");
+ }
+ return entriesByName.getNodeEntry(nodeName, index);
+ }
+
+ /**
+ * @see ChildNodeEntries#get(QName, String)
+ */
+ public NodeEntry get(QName nodeName, String uniqueID) {
+ if (uniqueID == null || nodeName == null) {
+ throw new IllegalArgumentException();
+ }
+ Iterator cneIter = get(nodeName).iterator();
+ while (cneIter.hasNext()) {
+ NodeEntry cne = (NodeEntry) cneIter.next();
+ if (uniqueID.equals(cne.getUniqueID())) {
+ return cne;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see ChildNodeEntries#get(ChildInfo)
+ */
+ public NodeEntry get(ChildInfo childInfo) {
+ String uniqueID = childInfo.getUniqueID();
+ NodeEntry child = null;
+ if (uniqueID != null) {
+ child = get(childInfo.getName(), uniqueID);
+ }
+ // try to load the child entry by name and index.
+ // this is required in case of a null uniqueID OR if the child entry has
+ // been created but never been resolved and therefore the uniqueID might
+ // be unknown.
+ if (child == null) {
+ int index = childInfo.getIndex();
+ child = entriesByName.getNodeEntry(childInfo.getName(), index);
+ }
+ return child;
+ }
+
+ /**
+ * Adds a <code>NodeEntry</code> to the end of the list. Same as
+ * {@link #add(NodeEntry, int)}, where the index is {@link Path#INDEX_UNDEFINED}.
+ *
+ * @param cne the <code>NodeEntry</code> to add.
+ * @see ChildNodeEntries#add(NodeEntry)
+ */
+ public void add(NodeEntry cne) {
+ internalAdd(cne, Path.INDEX_UNDEFINED);
+ }
+
+ /**
+ * @see ChildNodeEntries#add(NodeEntry, int)
+ */
+ public void add(NodeEntry cne, int index) {
+ if (index < Path.INDEX_UNDEFINED) {
+ throw new IllegalArgumentException("Invalid index" + index);
+ }
+ internalAdd(cne, index);
+ }
+
+ /**
+ *
+ * @param entry
+ * @param index
+ * @return
+ */
+ private LinkedEntries.LinkNode internalAdd(NodeEntry entry, int index) {
+ QName nodeName = entry.getQName();
+
+ // retrieve ev. sibling node with same index. if index is 'undefined'
+ // the existing entry is always null and no reordering occurs.
+ LinkedEntries.LinkNode existing = null;
+ if (index >= Path.INDEX_DEFAULT) {
+ existing = entriesByName.getLinkNode(nodeName, index);
+ }
+
+ // in case index greater than default -> create intermediate entries.
+ // TODO: TOBEFIXED in case of orderable node the order in the 'linked-entries' must be respected.
+ for (int i = Path.INDEX_DEFAULT; i < index; i++) {
+ LinkedEntries.LinkNode previous = entriesByName.getLinkNode(nodeName, i);
+ if (previous == null) {
+ NodeEntry sibling = factory.createNodeEntry(parent, nodeName, null);
+ internalAdd(sibling, i);
+ }
+ }
+
+ // add new entry
+ LinkedEntries.LinkNode ln = entries.add(entry);
+ entriesByName.put(nodeName, ln);
+
+ // reorder the child entries if, the new entry must be inserted rather
+ // than appended at the end of the list.
+ if (existing != null) {
+ reorder(nodeName, ln, existing);
+ }
+ return ln;
+ }
+
+ /**
+ * @see ChildNodeEntries#add(NodeEntry, NodeEntry)
+ */
+ public void add(NodeEntry entry, NodeEntry beforeEntry) {
+ if (beforeEntry != null) {
+ // the link node where the new entry is ordered before
+ LinkedEntries.LinkNode beforeLN = entries.getLinkNode(beforeEntry);
+ if (beforeLN == null) {
+ throw new NoSuchElementException();
+ }
+ LinkedEntries.LinkNode insertLN = internalAdd(entry, Path.INDEX_UNDEFINED);
+ reorder(entry.getQName(), insertLN, beforeLN);
+ } else {
+ // 'before' is null -> simply append new entry at the end
+ add(entry);
+ }
+ }
+
+ /**
+ * Removes the child node entry refering to the node state.
+ *
+ * @param childEntry the entry to be removed.
+ * @return the removed entry or <code>null</code> if there is no such entry.
+ * @see ChildNodeEntries#remove(NodeEntry)
+ */
+ public synchronized NodeEntry remove(NodeEntry childEntry) {
+ LinkedEntries.LinkNode ln = entries.removeNodeEntry(childEntry);
+ if (ln != null) {
+ entriesByName.remove(childEntry.getQName(), ln);
+ return childEntry;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Reorders an existing <code>NodeState</code> before another
+ * <code>NodeState</code>. If <code>beforeNode</code> is
+ * <code>null</code> <code>insertNode</code> is moved to the end of the
+ * child node entries.
+ *
+ * @param insertNode the NodeEntry to move.
+ * @param beforeNode the NodeEntry where <code>insertNode</code> is
+ * reordered to.
+ * @return the NodeEntry that followed the 'insertNode' before the reordering.
+ * @throws NoSuchElementException if <code>insertNode</code> or
+ * <code>beforeNode</code> does not have a <code>NodeEntry</code>
+ * in this <code>ChildNodeEntries</code>.
+ * @see ChildNodeEntries#reorder(NodeEntry, NodeEntry)
+ */
+ public NodeEntry reorder(NodeEntry insertEntry, NodeEntry beforeEntry) {
+ // the link node to move
+ LinkedEntries.LinkNode insertLN = entries.getLinkNode(insertEntry);
+ if (insertLN == null) {
+ throw new NoSuchElementException();
+ }
+ // the link node where insertLN is ordered before
+ LinkedEntries.LinkNode beforeLN = (beforeEntry != null) ? entries.getLinkNode(beforeEntry) : null;
+ if (beforeEntry != null && beforeLN == null) {
+ throw new NoSuchElementException();
+ }
+
+ NodeEntry previousBefore = insertLN.getNextLinkNode().getNodeEntry();
+ if (previousBefore != beforeEntry) {
+ reorder(insertEntry.getQName(), insertLN, beforeLN);
+ }
+ return previousBefore;
+ }
+
+ /**
+ *
+ * @param insertObj
+ * @param insertLN
+ * @param beforeLN
+ */
+ private void reorder(QName insertName, LinkedEntries.LinkNode insertLN, LinkedEntries.LinkNode beforeLN) {
+ // reorder named map
+ if (entriesByName.containsSiblings(insertName)) {
+ int position;
+ if (beforeLN == null) {
+ // reorder to the end -> use illegal position as marker
+ position = - 1;
+ } else {
+ // count all SNS-entries that are before 'beforeLN' in order to
+ // determine the new position of the reordered node regarding
+ // his siblings.
+ position = 0;
+ for (Iterator it = entries.linkNodeIterator(); it.hasNext(); ) {
+ LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
+ if (ln == beforeLN) {
+ break;
+ } else if (ln != insertLN && ln.getNodeEntry().getQName().equals(insertName)) {
+ position++;
+ } // else: ln == inserLN OR no SNS -> not relevant for position count
+ }
+ }
+ entriesByName.reorder(insertName, insertLN, position);
+ }
+ // reorder in linked list
+ entries.reorderNode(insertLN, beforeLN);
+ }
+
+ //-------------------------------------------------< AbstractLinkedList >---
+ /**
+ * An implementation of a linked list which provides access to the internal
+ * LinkNode which links the entries of the list.
+ */
+ private final class LinkedEntries extends AbstractLinkedList {
+
+ LinkedEntries() {
+ super();
+ init();
+ }
+
+ /**
+ * Returns the matching <code>LinkNode</code> from a list or a single
+ * <code>LinkNode</code>. This method will return <code>null</code>
+ * if none of the entries matches either due to missing entry for given
+ * state name or due to missing availability of the <code>NodeEntry</code>.
+ *
+ * @param nodeEntry the <code>NodeEntry</code> that is compared to the
+ * resolution of any <code>NodeEntry</code> that matches by name.
+ * @return the matching <code>LinkNode</code> or <code>null</code>
+ */
+ private LinkedEntries.LinkNode getLinkNode(NodeEntry nodeEntry) {
+ for (Iterator it = linkNodeIterator(); it.hasNext();) {
+ LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
+ if (ln.getNodeEntry() == nodeEntry) {
+ return ln;
+ }
+ }
+ // not found
+ return null;
+ }
+
+ /**
+ * Adds a child node entry to this list.
+ *
+ * @param cne the child node entry to add.
+ * @return the LinkNode which refers to the added <code>NodeEntry</code>.
+ */
+ LinkedEntries.LinkNode add(NodeEntry cne) {
+ LinkedEntries.LinkNode ln = new LinkedEntries.LinkNode(cne);
+ addNode(ln, header);
+ return ln;
+ }
+
+ /**
+ * Remove the LinkEntry the contains the given NodeEntry as value.
+ *
+ * @param cne NodeEntry to be removed.
+ * @return LinkedEntries.LinkNode that has been removed.
+ */
+ LinkedEntries.LinkNode removeNodeEntry(NodeEntry cne) {
+ LinkedEntries.LinkNode ln = getLinkNode(cne);
+ if (ln != null) {
+ ln.remove();
+ }
+ return ln;
+ }
+
+ /**
+ * Reorders an existing <code>LinkNode</code> before another existing
+ * <code>LinkNode</code>. If <code>before</code> is <code>null</code>
+ * the <code>insert</code> node is moved to the end of the list.
+ *
+ * @param insert the node to reorder.
+ * @param before the node where to reorder node <code>insert</code>.
+ */
+ void reorderNode(LinkedEntries.LinkNode insert, LinkedEntries.LinkNode before) {
+ removeNode(insert);
+ if (before == null) {
+ addNode(insert, header);
+ } else {
+ addNode(insert, before);
+ }
+ }
+
+ /**
+ * Create a new <code>LinkNode</code> for a given {@link NodeEntry}
+ * <code>value</code>.
+ *
+ * @param value a child node entry.
+ * @return a wrapping {@link LinkedEntries.LinkNode}.
+ * @see AbstractLinkedList#createNode(Object)
+ */
+ protected Node createNode(Object value) {
+ return new LinkedEntries.LinkNode(value);
+ }
+
+ /**
+ * @return a new <code>LinkNode</code>.
+ * @see AbstractLinkedList#createHeaderNode()
+ */
+ protected Node createHeaderNode() {
+ return new LinkedEntries.LinkNode();
+ }
+
+ /**
+ * @return iterator over all LinkNode entries in this list.
+ */
+ private Iterator linkNodeIterator() {
+ return new LinkNodeIterator();
+ }
+
+ //----------------------------------------------------------------------
+ /**
+ * Extends the <code>AbstractLinkedList.Node</code>.
+ */
+ private final class LinkNode extends Node {
+
+ private final QName qName;
+
+ protected LinkNode() {
+ super();
+ qName = null;
+ }
+
+ protected LinkNode(Object value) {
+ super(new WeakReference(value));
+ qName = ((NodeEntry) value).getQName();
+ }
+
+ protected void setValue(Object value) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ protected Object getValue() {
+ WeakReference val = (WeakReference) super.getValue();
+ // if the nodeEntry has been g-collected in the mean time
+ // create a new NodeEntry in order to avoid returning null.
+ NodeEntry ne = (val == null) ? null : (NodeEntry) val.get();
+ if (ne == null && this != header) {
+ ne = factory.createNodeEntry(parent, qName, null);
+ super.setValue(new WeakReference(ne));
+ }
+ return ne;
+ }
+
+ /**
+ * @return the wrapped <code>NodeEntry</code>.
+ */
+ public NodeEntry getNodeEntry() {
+ return (NodeEntry) getValue();
+ }
+
+ /**
+ * Removes this <code>LinkNode</code> from the linked list.
+ */
+ public void remove() {
+ removeNode(this);
+ }
+
+ /**
+ * @return the next LinkNode.
+ */
+ public LinkedEntries.LinkNode getNextLinkNode() {
+ return (LinkedEntries.LinkNode) super.getNextNode();
+ }
+ }
+
+ //----------------------------------------------------------------------
+ private class LinkNodeIterator implements Iterator {
+
+ private LinkedEntries.LinkNode next = ((LinkedEntries.LinkNode) header).getNextLinkNode();
+ private int expectedModCount = modCount;
+
+ public boolean hasNext() {
+ checkModCount();
+ return next != header;
+ }
+
+ public Object next() {
+ checkModCount();
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ LinkedEntries.LinkNode n = next;
+ next = next.getNextLinkNode();
+ return n;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+
+ private void checkModCount() {
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+ }
+
+
+
+ //--------------------------------------------------------------------------
+ /**
+ * Mapping of QName to LinkNode OR List of LinkNode(s) in case of SNSiblings.
+ */
+ private static class NameMap {
+
+ private Map snsMap = new HashMap();
+ private Map nameMap = new HashMap();
+
+ /**
+ * Return true if more than one NodeEnty with the given name exists.
+ *
+ * @param qName
+ * @return
+ */
+ public boolean containsSiblings(QName qName) {
+ return snsMap.containsKey(qName);
+ }
+
+ /**
+ * Returns a single <code>NodeEntry</code> or an unmodifiable
+ * <code>List</code> of NodeEntry objects.
+ *
+ * @param qName
+ * @return a single <code>NodeEntry</code> or a <code>List</code> of
+ * NodeEntry objects.
+ */
+ private Object get(QName qName) {
+ Object val = nameMap.get(qName);
+ if (val != null) {
+ return ((LinkedEntries.LinkNode) val).getNodeEntry();
+ } else {
+ List l = (List) snsMap.get(qName);
+ if (l != null) {
+ List nodeEntries = new ArrayList(l.size());
+ for (Iterator it = l.iterator(); it.hasNext();) {
+ LinkedEntries.LinkNode ln = (LinkedEntries.LinkNode) it.next();
+ nodeEntries.add(ln.getNodeEntry());
+ }
+ return nodeEntries;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a unmodifiable List of NodeEntry objects even if the name map
+ * only contains a single entry for the given name. If no matching entry
+ * exists for the given qualified name an empty list is returned.
+ *
+ * @param qName
+ * @return
+ */
+ public List getList(QName qName) {
+ Object obj = get(qName);
+ if (obj == null) {
+ return Collections.EMPTY_LIST;
+ } else if (obj instanceof List) {
+ List l = new ArrayList((List)obj);
+ return Collections.unmodifiableList(l);
+ } else {
+ // NodeEntry
+ return Collections.singletonList(obj);
+ }
+ }
+
+ public NodeEntry getNodeEntry(QName qName, int index) {
+ Object obj = get(qName);
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof List) {
+ // map entry is a list of siblings
+ return findMatchingEntry((List) obj, index);
+ } else {
+ // map entry is a single child node entry
+ if (index == Path.INDEX_DEFAULT) {
+ return (NodeEntry) obj;
+ }
+ }
+ return null;
+ }
+
+ public LinkedEntries.LinkNode getLinkNode(QName qName, int index) {
+ if (index < Path.INDEX_DEFAULT) {
+ throw new IllegalArgumentException("Illegal index " + index);
+ }
+
+ LinkedEntries.LinkNode val = (LinkedEntries.LinkNode) nameMap.get(qName);
+ if (val != null) {
+ return (index == Path.INDEX_DEFAULT) ? val : null;
+ } else {
+ // look in snsMap
+ List l = (List) snsMap.get(qName);
+ int pos = index - 1; // Index of NodeEntry is 1-based
+ return (l != null && pos < l.size()) ? (LinkedEntries.LinkNode) l.get(pos) : null;
+ }
+ }
+
+ public void put(QName qName, LinkedEntries.LinkNode value) {
+ // if 'nameMap' already contains a single entry -> move it to snsMap
+ LinkedEntries.LinkNode single = (LinkedEntries.LinkNode) nameMap.remove(qName);
+ List l;
+ if (single != null) {
+ l = new ArrayList();
+ l.add(single);
+ snsMap.put(qName, l);
+ } else {
+ // if 'snsMap' already contains list
+ l = (List) snsMap.get(qName);
+ }
+
+ if (l == null) {
+ nameMap.put(qName, value);
+ } else {
+ l.add(value);
+ }
+ }
+
+ public LinkedEntries.LinkNode remove(QName qName, LinkedEntries.LinkNode value) {
+ Object rm = nameMap.remove(qName);
+ if (rm == null) {
+ List l = (List) snsMap.get(qName);
+ if (l != null && l.remove(value)) {
+ rm = value;
+ }
+ }
+ return ((LinkedEntries.LinkNode) rm);
+ }
+
+ public void reorder(QName qName, LinkedEntries.LinkNode insertValue, int position) {
+ List sns = (List) snsMap.get(qName);
+ if (sns == null) {
+ // no same name siblings -> no special handling required
+ return;
+ }
+ // reorder sns in the name-list
+ if (position < 0) {
+ // simply move to end of list
+ sns.remove(insertValue);
+ sns.add(insertValue);
+ } else {
+ sns.remove(insertValue);
+ sns.add(position, insertValue);
+ }
+ }
+
+ /**
+ *
+ * @param siblings
+ * @param index
+ * @param checkValidity
+ * @return
+ */
+ private static NodeEntry findMatchingEntry(List siblings, int index) {
+ // shortcut if index can never match
+ if (index > siblings.size()) {
+ return null;
+ } else {
+ return (NodeEntry) siblings.get(index - 1);
+ }
+ }
+ }
+}
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildNodeEntriesImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java?view=auto&rev=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java Tue May 29 08:51:30 2007
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jcr2spi.hierarchy;
+
+import org.apache.jackrabbit.name.QName;
+
+import java.util.Collection;
+
+/**
+ * <code>ChildPropertyEntries</code>...
+ */
+public interface ChildPropertyEntries {
+
+ /**
+ * Returns true if a property entry with the given name exists.
+ *
+ * @param propertyName
+ * @return true if a property entry with the given name exists.
+ */
+ public boolean contains(QName propertyName);
+
+ /**
+ * Return the PropertyEntry with the given <code>QName</code> or
+ * <code>null</code>.
+ *
+ * @param propertyName
+ * @return
+ */
+ public PropertyEntry get(QName propertyName);
+
+ /**
+ * Returns an unmodifiable collection containing all <code>PropertyEntry</code>
+ * objects present.
+ *
+ * @return Collection of all <code>PropertyEntry</code> objects present.
+ */
+ public Collection getPropertyEntries();
+
+ /**
+ * Returns an unmodifiable collection containing all existing property names.
+ *
+ * @return Collection of <code>QName</code>
+ */
+ public Collection getPropertyNames();
+
+ /**
+ * Adds the new <code>PropertyEntry</code> to this <code>ChildPropertyEntries</code>.
+ *
+ * @param propertyEntry
+ */
+ public void add(PropertyEntry propertyEntry);
+
+ /**
+ * Adds all <code>PropertyEntry</code>s from the given collection to this
+ * <code>ChildPropertyEntries</code>.
+ *
+ * @param propertyEntries
+ */
+ public void addAll(Collection propertyEntries);
+
+ /**
+ * Remove the collection entry with the given <code>QName</code>.
+ *
+ * @param propertyName
+ * @return true If this <code>ChildPropertyEntries</code> contained any
+ * entry with the given <code>QName</code>. False otherwise.
+ */
+ public boolean remove(QName propertyName);
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntries.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java?view=auto&rev=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java Tue May 29 08:51:30 2007
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jcr2spi.hierarchy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.name.QName;
+
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ * <code>ChildPropertyEntriesImpl</code>...
+ */
+public class ChildPropertyEntriesImpl implements ChildPropertyEntries {
+
+ private static Logger log = LoggerFactory.getLogger(ChildPropertyEntriesImpl.class);
+
+ private final Map properties;
+ private final NodeEntry parent;
+ private final EntryFactory factory;
+
+ ChildPropertyEntriesImpl(NodeEntry parent, EntryFactory factory) {
+ properties = new HashMap();
+ this.parent = parent;
+ this.factory = factory;
+ }
+
+ /**
+ * @see ChildPropertyEntries#contains(QName)
+ */
+ public boolean contains(QName propertyName) {
+ return properties.containsKey(propertyName);
+ }
+
+ /**
+ * @see ChildPropertyEntries#get(QName)
+ */
+ public PropertyEntry get(QName propertyName) {
+ Object ref = properties.get(propertyName);
+ if (ref == null) {
+ // no entry exists with the given name
+ return null;
+ }
+
+ PropertyEntry entry = (PropertyEntry) ((Reference) ref).get();
+ if (entry == null) {
+ // entry has been g-collected -> create new entry and return it.
+ entry = factory.createPropertyEntry(parent, propertyName);
+ add(entry);
+ }
+ return entry;
+ }
+
+ /**
+ * @see ChildPropertyEntries#getPropertyEntries()
+ */
+ public Collection getPropertyEntries() {
+ synchronized (properties) {
+ Set entries = new HashSet(properties.size());
+ for (Iterator it = getPropertyNames().iterator(); it.hasNext();) {
+ QName propName = (QName) it.next();
+ entries.add(get(propName));
+ }
+ return Collections.unmodifiableCollection(entries);
+ }
+ }
+
+ /**
+ * @see ChildPropertyEntries#getPropertyNames()
+ */
+ public Collection getPropertyNames() {
+ return properties.keySet();
+ }
+
+ /**
+ * @see ChildPropertyEntries#add(PropertyEntry)
+ */
+ public void add(PropertyEntry propertyEntry) {
+ WeakReference ref = new WeakReference(propertyEntry);
+ properties.put(propertyEntry.getQName(), ref);
+ }
+
+ /**
+ * @see ChildPropertyEntries#addAll(Collection)
+ */
+ public void addAll(Collection propertyEntries) {
+ for (Iterator it = propertyEntries.iterator(); it.hasNext();) {
+ Object pe = it.next();
+ if (pe instanceof PropertyEntry) {
+ add((PropertyEntry) pe);
+ }
+ }
+ }
+
+ /**
+ * @see ChildPropertyEntries#remove(QName)
+ */
+ public boolean remove(QName propertyName) {
+ WeakReference ref = (WeakReference) properties.remove(propertyName);
+ return ref != null;
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/ChildPropertyEntriesImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryFactory.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryFactory.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/EntryFactory.java Tue May 29 08:51:30 2007
@@ -20,6 +20,7 @@
import org.slf4j.LoggerFactory;
import org.apache.jackrabbit.jcr2spi.state.TransientItemStateFactory;
import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.jackrabbit.name.QName;
/**
* <code>EntryFactory</code>...
@@ -58,6 +59,20 @@
*/
public NodeEntry createRootEntry() {
return rootEntry;
+ }
+
+ public NodeEntry createNodeEntry(NodeEntry parent, QName qName, String uniqueId) {
+ if (!(parent instanceof NodeEntryImpl)) {
+ throw new IllegalArgumentException();
+ }
+ return NodeEntryImpl.createNodeEntry((NodeEntryImpl) parent, qName, uniqueId, this);
+ }
+
+ public PropertyEntry createPropertyEntry(NodeEntry parent, QName qName) {
+ if (!(parent instanceof NodeEntryImpl)) {
+ throw new IllegalArgumentException();
+ }
+ return PropertyEntryImpl.create((NodeEntryImpl) parent, qName, this);
}
public IdFactory getIdFactory() {
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/HierarchyEntryImpl.java Tue May 29 08:51:30 2007
@@ -39,7 +39,6 @@
/**
* Cached weak reference to the target ItemState.
- * // TODO: check correct?
*/
private WeakReference target;
@@ -49,7 +48,7 @@
protected QName name;
/**
- * The parent <code>HierarchyEntry</code>.
+ * Hard reference to the parent <code>NodeEntry</code>.
*/
protected NodeEntryImpl parent;
@@ -319,7 +318,7 @@
remove();
} catch (RepositoryException e) {
// TODO: rather throw? remove from parent?
- log.warn("Exception while reloading property state: " + e);
+ log.warn("Exception while reloading item state: " + e);
log.debug("Stacktrace: ", e);
}
}
Modified: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java?view=diff&rev=542571&r1=542570&r2=542571
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java (original)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/hierarchy/NodeEntry.java Tue May 29 08:51:30 2007
@@ -142,16 +142,20 @@
public NodeEntry getNodeEntry(QName nodeName, int index) throws RepositoryException;
/**
- * Returns the <code>NodeEntry</code> with the specified
- * <code>NodeId</code> or <code>null</code> if there's no matching
- * entry.
- *
- * @param childId the id of the child entry.
- * @return the <code>NodeEntry</code> with the specified
- * <code>NodeId</code> or <code>null</code> if there's no matching entry.
+ * Returns the valid <code>NodeEntry</code> with the specified name
+ * and index or <code>null</code> if there's no matching entry. If
+ * <code>loadIfNotFound</code> is true, the implementation must make
+ * sure, that it's list of child entries is up to date and eventually
+ * try to load the node entry.
+ *
+ * @param nodeName <code>QName</code> object specifying a node name.
+ * @param index 1-based index if there are same-name child node entries.
+ * @param loadIfNotFound
+ * @return The <code>NodeEntry</code> with the specified name and index
+ * or <code>null</code> if there's no matching entry.
* @throws RepositoryException If an unexpected error occurs.
*/
- public NodeEntry getNodeEntry(NodeId childId) throws RepositoryException;
+ public NodeEntry getNodeEntry(QName nodeName, int index, boolean loadIfNotFound) throws RepositoryException;
/**
* Returns a unmodifiable iterator of <code>NodeEntry</code> objects
@@ -210,8 +214,24 @@
* @param propName <code>QName</code> object specifying a property name.
* @return The <code>PropertyEntry</code> with the specified name or
* <code>null</code> if no matching entry exists.
+ * @throws RepositoryException If an unexpected error occurs.
*/
- public PropertyEntry getPropertyEntry(QName propName);
+ public PropertyEntry getPropertyEntry(QName propName) throws RepositoryException;
+
+ /**
+ * Returns the valid <code>PropertyEntry</code> with the specified name
+ * or <code>null</code> if no matching entry exists. If
+ * <code>loadIfNotFound</code> is true, the implementation must make
+ * sure, that it's list of property entries is up to date and eventually
+ * try to load the property entry with the given name.
+ *
+ * @param propName <code>QName</code> object specifying a property name.
+ * @param loadIfNotFound
+ * @return The <code>PropertyEntry</code> with the specified name or
+ * <code>null</code> if no matching entry exists.
+ * @throws RepositoryException If an unexpected error occurs.
+ */
+ public PropertyEntry getPropertyEntry(QName propName, boolean loadIfNotFound) throws RepositoryException;
/**
* Returns an unmodifiable Iterator over those children that represent valid
@@ -222,9 +242,12 @@
public Iterator getPropertyEntries();
/**
+ * Add an existing <code>PropertyEntry</code> with the given name.
+ * Please note the difference to {@link #addNewPropertyEntry(QName, QPropertyDefinition)
+ * which adds a new, transient entry.
*
* @param propName
- * @return
+ * @return the <code>PropertyEntry</code>
* @throws ItemExistsException if a child item exists with the given name
* @throws RepositoryException if an unexpected error occurs.
*/
@@ -243,6 +266,8 @@
public void addPropertyEntries(Collection propNames) throws ItemExistsException, RepositoryException;
/**
+ * Add a new, transient <code>PropertyEntry</code> to this <code>NodeEntry</code>
+ * and return the <code>PropertyState</code> associated with the new entry.
*
* @param propName
* @return The PropertyState associated with the new property entry.
@@ -262,6 +287,13 @@
public void orderBefore(NodeEntry beforeEntry) throws RepositoryException;
/**
+ * Moves this <code>NodeEntry</code> as new child entry of the
+ * <code>NodeEntry</code> identified by <code>newParent</code> and/or renames
+ * it to <code>newName</code>. If <code>transientMove</code> is true, an
+ * implementation must make sure, that reverting this modification by calling
+ * {@link HierarchyEntry#revert()} on the common ancestor of both parents
+ * moves this NodeEntry back and resets the name to its original value.
+ *
* @param newName
* @param newParent
* @return the moved entry