You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/04/24 11:10:29 UTC
svn commit: r651202 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java
Author: dpfister
Date: Thu Apr 24 02:10:23 2008
New Revision: 651202
URL: http://svn.apache.org/viewvc?rev=651202&view=rev
Log:
JCR-1104 - JSR 283 support
- shareble nodes (work in progress)
- cache multiple paths to same (shareable) node
- simplify eviction of cached paths
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java?rev=651202&r1=651201&r2=651202&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Thu Apr 24 02:10:23 2008
@@ -146,7 +146,7 @@
protected void pathResolved(ItemId id, PathBuilder builder)
throws MalformedPathException {
- if (id.denotesNode() && !isCached(id)) {
+ if (id.denotesNode()) {
cache((NodeId) id, builder.getPath());
}
}
@@ -295,26 +295,24 @@
// Item not cached, ignore
return;
}
+ PathMap.Element[] elements = entry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ Iterator iter = elements[i].getChildren();
+ while (iter.hasNext()) {
+ PathMap.Element child = (PathMap.Element) iter.next();
+ NodeState.ChildNodeEntry cne = modified.getChildNodeEntry(
+ child.getName(), child.getNormalizedIndex());
+ if (cne == null) {
+ // Item does not exist, remove
+ evict(child, true);
+ return;
+ }
- PathMap.Element element = entry.getElement();
-
- Iterator iter = element.getChildren();
- while (iter.hasNext()) {
- PathMap.Element child = (PathMap.Element) iter.next();
- NodeState.ChildNodeEntry cne = modified.getChildNodeEntry(
- child.getName(), child.getNormalizedIndex());
- if (cne == null) {
- // Item does not exist, remove
- child.remove();
- remove(child);
- return;
- }
-
- LRUEntry childEntry = (LRUEntry) child.get();
- if (childEntry != null && !cne.getId().equals(childEntry.getId())) {
- // Different child item, remove
- child.remove();
- remove(child);
+ LRUEntry childEntry = (LRUEntry) child.get();
+ if (childEntry != null && !cne.getId().equals(childEntry.getId())) {
+ // Different child item, remove
+ evict(child, true);
+ }
}
}
}
@@ -324,7 +322,7 @@
* {@inheritDoc}
*/
public void stateDestroyed(ItemState destroyed) {
- remove(destroyed.getId());
+ evictAll(destroyed.getId(), true);
}
/**
@@ -334,11 +332,11 @@
if (discarded.isTransient() && !discarded.hasOverlayedState()
&& discarded.getStatus() == ItemState.STATUS_NEW) {
// a new node has been discarded -> remove from cache
- remove(discarded.getId());
+ evictAll(discarded.getId(), true);
} else if (provider.hasItemState(discarded.getId())) {
- evict(discarded.getId());
+ evictAll(discarded.getId(), false);
} else {
- remove(discarded.getId());
+ evictAll(discarded.getId(), true);
}
}
@@ -377,12 +375,15 @@
public void nodesReplaced(NodeState state) {
synchronized (cacheMonitor) {
LRUEntry entry = (LRUEntry) idCache.get(state.getNodeId());
- if (entry != null) {
- PathMap.Element parent = entry.getElement();
+ if (entry == null) {
+ return;
+ }
+ PathMap.Element[] parents = entry.getElements();
+ for (int i = 0; i < parents.length; i++) {
HashMap newChildrenOrder = new HashMap();
boolean orderChanged = false;
- Iterator iter = parent.getChildren();
+ Iterator iter = parents[i].getChildren();
while (iter.hasNext()) {
PathMap.Element child = (PathMap.Element) iter.next();
LRUEntry childEntry = (LRUEntry) child.get();
@@ -393,16 +394,14 @@
* position is still accurate and have to assume
* the worst and remove it.
*/
- child.remove(false);
- remove(child);
+ evict(child, false);
continue;
}
NodeId childId = childEntry.getId();
NodeState.ChildNodeEntry cne = state.getChildNodeEntry(childId);
if (cne == null) {
/* Child no longer in parent node state, so remove it */
- child.remove(false);
- remove(child);
+ evict(child, false);
continue;
}
@@ -422,7 +421,7 @@
if (orderChanged) {
/* If at least one child changed its position, reorder */
- parent.setChildren(newChildrenOrder);
+ parents[i].setChildren(newChildrenOrder);
}
}
}
@@ -443,6 +442,8 @@
+ ", event ignored.");
} catch (MalformedPathException e) {
log.warn("Unable to create path of " + id, e);
+ } catch (ItemStateException e) {
+ log.warn("Unable to find item " + id, e);
} catch (ItemNotFoundException e) {
log.warn("Unable to get path of " + state.getNodeId(), e);
} catch (RepositoryException e) {
@@ -455,7 +456,7 @@
//------------------------------------------------------< private methods >
/**
- * Return a cached element in the path map, given its id
+ * Return the first cached path that is mapped to given id.
*
* @param id node id
* @return cached element, <code>null</code> if not found
@@ -465,7 +466,7 @@
LRUEntry entry = (LRUEntry) idCache.get(id);
if (entry != null) {
entry.touch();
- return entry.getElement();
+ return entry.getElements()[0];
}
return null;
}
@@ -502,150 +503,138 @@
*/
private void cache(NodeId id, Path path) {
synchronized (cacheMonitor) {
- if (idCache.get(id) != null) {
+ if (isCached(id, path)) {
return;
}
if (idCache.size() >= upperLimit) {
/**
- * Remove least recently used item. Scans the LRU list from head to tail
- * and removes the first item that has no children.
+ * Remove least recently used item. Scans the LRU list from
+ * head to tail and removes the first item that has no children.
*/
LRUEntry entry = head;
while (entry != null) {
- PathMap.Element element = entry.getElement();
- if (element.getChildrenCount() == 0) {
- evict(entry, true);
+ PathMap.Element[] elements = entry.getElements();
+ int childrenCount = 0;
+ for (int i = 0; i < elements.length; i++) {
+ childrenCount += elements[i].getChildrenCount();
+ }
+ if (childrenCount == 0) {
+ evictAll(entry.getId(), false);
return;
}
entry = entry.getNext();
}
}
-
PathMap.Element element = pathCache.put(path);
if (element.get() != null) {
if (!id.equals(((LRUEntry) element.get()).getId())) {
log.warn("overwriting PathMap.Element");
}
}
- LRUEntry entry = new LRUEntry(id, element);
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry == null) {
+ entry = new LRUEntry(id, element);
+ idCache.put(id, entry);
+ } else {
+ entry.addElement(element);
+ }
element.set(entry);
- idCache.put(id, entry);
}
}
/**
- * Return a flag indicating whether a certain element is cached.
+ * Return a flag indicating whether a certain node and/or path is cached.
+ * If <code>path</code> is <code>null</code>, check whether the item is
+ * cached at all. If <code>path</code> is <b>not</b> <code>null</code>,
+ * check whether the item is cached with that path.
*
* @param id item id
+ * @param path path, may be <code>null</code>
* @return <code>true</code> if the item is already cached;
* <code>false</code> otherwise
*/
- boolean isCached(ItemId id) {
+ boolean isCached(NodeId id, Path path) {
synchronized (cacheMonitor) {
- return idCache.get(id) != null;
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry == null) {
+ return false;
+ }
+ if (path == null) {
+ return true;
+ }
+ PathMap.Element[] elements = entry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i].hasPath(path)) {
+ return true;
+ }
+ }
+ return false;
}
}
/**
- * Remove item from cache. Removes the associated <code>LRUEntry</code>
- * and the <code>PathMap.Element</code> with it. Indexes of same name
- * sibling elements are shifted!
+ * Return a flag indicating whether a certain path is cached.
*
* @param id item id
+ * @return <code>true</code> if the item is already cached;
+ * <code>false</code> otherwise
*/
- private void remove(ItemId id) {
+ boolean isCached(Path path) {
synchronized (cacheMonitor) {
- LRUEntry entry = (LRUEntry) idCache.get(id);
- if (entry != null) {
- remove(entry, true);
+ PathMap.Element element = pathCache.map(path, true);
+ if (element != null) {
+ return element.get() != null;
}
+ return false;
}
}
/**
- * Remove item from cache. Index of same name sibling items are shifted!
- * If <code>removeFromPathCache</code> is <code>true</code>, the path map
- * element associated with <code>entry</code> is deleted recursively and
- * every associated element is removed.
- * If <code>removeFromPathCache</code> is <code>false</code>, only the
- * LRU entry is removed from the cache.
- *
- * @param entry LRU entry
- * @param removeFromPathCache whether to remove from path cache
- */
- private void remove(LRUEntry entry, boolean removeFromPathCache) {
- // assert: synchronized (cacheMonitor)
- if (removeFromPathCache) {
- PathMap.Element element = entry.getElement();
- remove(element);
- element.remove();
- } else {
- idCache.remove(entry.getId());
- entry.remove();
- }
- }
-
- /**
- * Evict item from cache. Index of same name sibling items are <b>not</b>
- * shifted!
- *
- * @param entry LRU entry
- * @param removeFromPathCache whether to remove from path cache
- */
- private void evict(LRUEntry entry, boolean removeFromPathCache) {
- // assert: synchronized (cacheMonitor)
- if (removeFromPathCache) {
- PathMap.Element element = entry.getElement();
- element.traverse(new PathMap.ElementVisitor() {
- public void elementVisited(PathMap.Element element) {
- evict((LRUEntry) element.get(), false);
- }
- }, false);
- element.remove(false);
- } else {
- idCache.remove(entry.getId());
- entry.remove();
- }
- }
-
- /**
- * Evict item from cache. Evicts the associated <code>LRUEntry</code>
- * and the <code>PathMap.Element</code> with it. Indexes of same name
- * sibling elements are <b>not</b> shifted!
+ * Remove all path mapping for a given item id. Removes the associated
+ * <code>LRUEntry</code> and the <code>PathMap.Element</code> with it.
+ * Indexes of same name sibling elements are shifted!
*
* @param id item id
*/
- private void evict(ItemId id) {
+ private void evictAll(ItemId id, boolean shift) {
synchronized (cacheMonitor) {
LRUEntry entry = (LRUEntry) idCache.get(id);
if (entry != null) {
- evict(entry, true);
+ PathMap.Element[] elements = entry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ evict(elements[i], shift);
+ }
}
}
}
/**
- * Remove path map element from cache. This will traverse all children
+ * Evict path map element from cache. This will traverse all children
* of this element and remove the objects associated with them.
* Index of same name sibling items are shifted!
*
* @param element path map element
*/
- private void remove(PathMap.Element element) {
+ private void evict(PathMap.Element element, boolean shift) {
// assert: synchronized (cacheMonitor)
element.traverse(new PathMap.ElementVisitor() {
public void elementVisited(PathMap.Element element) {
- remove((LRUEntry) element.get(), false);
+ LRUEntry entry = (LRUEntry) element.get();
+ if (entry.removeElement(element) == 0) {
+ idCache.remove(entry.getId());
+ entry.remove();
+ }
}
}, false);
+ element.remove(shift);
}
/**
* Invoked when a notification about a child node addition has been received.
*
- * @param state node state
- * @param path node path
- * @param id node id
+ * @param state node state where child was added
+ * @param path path to child node
+ * @param id child node id
*
* @throws PathNotFoundException if the path was not found
*/
@@ -657,21 +646,28 @@
LRUEntry entry = (LRUEntry) idCache.get(id);
if (entry != null) {
- element = entry.getElement();
-
- NodeState child = (NodeState) getItemState(id);
- if (!child.isShareable()) {
- element.remove();
- } else {
- element = null;
+ // child node already cached: this can have the following
+ // reasons:
+ // 1) node was moved, cached path is outdated
+ // 2) node was cloned, cached path is still valid
+ NodeState child = null;
+ if (hasItemState(id)) {
+ child = (NodeState) getItemState(id);
+ }
+ if (child == null || !child.isShareable()) {
+ PathMap.Element[] elements = entry.getElements();
+ element = elements[0];
+ for (int i = 0; i < elements.length; i++) {
+ elements[i].remove();
+ }
}
}
-
PathMap.Element parent = pathCache.map(path.getAncestor(1), true);
if (parent != null) {
parent.insert(path.getNameElement());
}
if (element != null) {
+ // store remembered element at new position
pathCache.put(path, element);
}
}
@@ -687,26 +683,38 @@
* @throws PathNotFoundException if the path was not found
*/
private void nodeRemoved(NodeState state, Path path, NodeId id)
- throws PathNotFoundException {
+ throws PathNotFoundException, ItemStateException {
synchronized (cacheMonitor) {
PathMap.Element parent = pathCache.map(path.getAncestor(1), true);
- if (parent != null) {
+ if (parent == null) {
+ return;
+ }
+ PathMap.Element element = parent.getDescendant(PathFactoryImpl.getInstance().create(
+ new Path.Element[] { path.getNameElement() }), true);
+ if (element != null) {
// with SNS, this might evict a child that is NOT the one
// having <code>id</code>, check first whether item has
// the id passed as argument
- PathMap.Element child = parent.getDescendant(PathFactoryImpl.getInstance().create(
- new Path.Element[] { path.getNameElement() }), true);
- if (child != null) {
- LRUEntry entry = (LRUEntry) child.get();
- if (entry != null && !entry.getId().equals(id)) {
- return;
- }
+ LRUEntry entry = (LRUEntry) element.get();
+ if (entry != null && !entry.getId().equals(id)) {
+ return;
}
- PathMap.Element element = parent.remove(path.getNameElement());
- if (element != null) {
- remove(element);
+ // if item is shareable, remove this path only, otherwise
+ // every path this item has been mapped to
+ NodeState child = null;
+ if (hasItemState(id)) {
+ child = (NodeState) getItemState(id);
}
+ if (child == null || !child.isShareable()) {
+ evictAll(id, true);
+ } else {
+ evict(element, true);
+ }
+ } else {
+ // element itself is not cached, but removal might cause SNS
+ // index shifting
+ parent.remove(path.getNameElement());
}
}
}
@@ -760,9 +768,9 @@
private final NodeId id;
/**
- * Element in path map
+ * Elements in path map
*/
- private final PathMap.Element element;
+ private PathMap.Element[] elements;
/**
* Create a new instance of this class
@@ -772,7 +780,7 @@
*/
public LRUEntry(NodeId id, PathMap.Element element) {
this.id = id;
- this.element = element;
+ this.elements = new PathMap.Element[] { element };
append();
}
@@ -848,12 +856,46 @@
}
/**
- * Return element in path map
+ * Return elements in path map that are mapped to <code>id</code>. If
+ * this entry is a shareable node or one of its descendant, it can
+ * be reached by more than one path.
*
* @return element in path map
*/
- public PathMap.Element getElement() {
- return element;
+ public PathMap.Element[] getElements() {
+ return elements;
+ }
+
+ /**
+ * Add a mapping to some element.
+ */
+ public void addElement(PathMap.Element element) {
+ PathMap.Element[] tmp = new PathMap.Element[elements.length + 1];
+ System.arraycopy(elements, 0, tmp, 0, elements.length);
+ tmp[elements.length] = element;
+ elements = tmp;
+ }
+
+ /**
+ * Remove a mapping to some element from this entry.
+ *
+ * @return number of mappings left
+ */
+ public int removeElement(PathMap.Element element) {
+ boolean found = false;
+ for (int i = 0; i < elements.length; i++) {
+ if (found) {
+ elements[i - 1] = elements[i];
+ } else if (elements[i] == element) {
+ found = true;
+ }
+ }
+ if (found) {
+ PathMap.Element[] tmp = new PathMap.Element[elements.length - 1];
+ System.arraycopy(elements, 0, tmp, 0, tmp.length);
+ elements = tmp;
+ }
+ return elements.length;
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java?rev=651202&r1=651201&r2=651202&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/CachingHierarchyManagerTest.java Thu Apr 24 02:10:23 2008
@@ -108,7 +108,7 @@
NodeState a = ism.addNode(ism.getRoot(), "a");
NodeState b = ism.addNode(a, "b");
- Path path = toPath("{}\t{}a\t{}b");
+ Path path = toPath("/a/b");
// /a/b points to node only
assertIsNodeId(cache.resolvePath(path));
@@ -149,6 +149,25 @@
//------------------------------------------------------------ caching tests
/**
+ * Add a SNS (same name sibling) and verify that cached paths are
+ * adapted accordingly.
+ */
+ public void testAddSNS() throws Exception {
+ StaticItemStateManager ism = new StaticItemStateManager();
+ cache = new CachingHierarchyManager(ism.getRootNodeId(), ism, null);
+ ism.setContainer(cache);
+ NodeState a = ism.addNode(ism.getRoot(), "a");
+ NodeState b1 = ism.addNode(a, "b");
+ Path path = cache.getPath(b1.getNodeId());
+ assertEquals(toPath("/a/b"), path);
+ NodeState b2 = ism.addNode(a, "b");
+ ism.orderBefore(b2, b1);
+ assertTrue(cache.isCached(b1.getNodeId(), null));
+ path = cache.getPath(b1.getNodeId());
+ assertEquals(toPath("/a/b[2]"), path);
+ }
+
+ /**
* Clone a node, cache its path and remove it afterwards. Should remove
* the cached path as well.
*/
@@ -161,13 +180,47 @@
NodeState b1 = ism.addNode(a1, "b1");
b1.addShare(b1.getParentId());
ism.cloneNode(b1, a2, "b2");
- ItemId id = cache.resolvePath(toPath("{}\t{}a1\t{}b1"));
- assertEquals(b1.getId(), id);
- id = cache.resolvePath(toPath("{}\t{}a2\t{}b2"));
+
+ Path path1 = toPath("/a1/b1");
+ Path path2 = toPath("/a2/b2");
+
+ assertNotNull(cache.resolvePath(path1));
+ assertTrue(cache.isCached(b1.getNodeId(), path1));
+
ism.removeNode(b1);
- assertNull("Path no longer valid: /a1/b1",
- cache.resolvePath(toPath("{}\t{}a1\t{}b1")));
- ism.removeNode((NodeState) ism.getItemState(id));
+
+ assertNull(cache.resolvePath(path1));
+ assertNotNull(cache.resolvePath(path2));
+ }
+
+ /**
+ * Clone a node, create a child and resolve its path in all valid
+ * combinations. Then, move the child away. Should remove the cached
+ * paths as well.
+ */
+ public void testCloneAndAddChildAndMove() throws Exception {
+ StaticItemStateManager ism = new StaticItemStateManager();
+ cache = new CachingHierarchyManager(ism.getRootNodeId(), ism, null);
+ ism.setContainer(cache);
+ NodeState a1 = ism.addNode(ism.getRoot(), "a1");
+ NodeState a2 = ism.addNode(ism.getRoot(), "a2");
+ NodeState b1 = ism.addNode(a1, "b1");
+ b1.addShare(b1.getParentId());
+ ism.cloneNode(b1, a2, "b2");
+ NodeState c = ism.addNode(b1, "c");
+
+ Path path1 = toPath("/a1/b1/c");
+ Path path2 = toPath("/a2/b2/c");
+
+ assertNotNull(cache.resolvePath(path1));
+ assertTrue(cache.isCached(c.getNodeId(), path1));
+ assertNotNull(cache.resolvePath(path2));
+ assertTrue(cache.isCached(c.getNodeId(), path2));
+
+ ism.moveNode(c, a1, "c");
+
+ assertNull(cache.resolvePath(path1));
+ assertNull(cache.resolvePath(path2));
}
/**
@@ -181,10 +234,10 @@
NodeState a2 = ism.addNode(ism.getRoot(), "a2");
NodeState b1 = ism.addNode(a1, "b1");
Path path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a1\t{}b1", path.toString());
+ assertEquals(toPath("/a1/b1"), path);
ism.moveNode(b1, a2, "b2");
path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a2\t{}b2", path.toString());
+ assertEquals(toPath("/a2/b2"), path);
}
/**
@@ -199,11 +252,11 @@
NodeState b2 = ism.addNode(a, "b");
NodeState b3 = ism.addNode(a, "b");
Path path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a\t{}b", path.toString());
+ assertEquals(toPath("/a/b"), path);
ism.orderBefore(b2, b1);
ism.orderBefore(b1, b3);
path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a\t{}b[2]", path.toString());
+ assertEquals(toPath("/a/b[2]"), path);
}
/**
@@ -217,9 +270,46 @@
NodeState b = ism.addNode(a, "b");
NodeState c = ism.addNode(b, "c");
cache.getPath(c.getNodeId());
- assertTrue(cache.isCached(c.getId()));
+ assertTrue(cache.isCached((NodeId) c.getId(), null));
ism.removeNode(b);
- assertFalse(cache.isCached(c.getId()));
+ assertFalse(cache.isCached((NodeId) c.getId(), null));
+ }
+
+ /**
+ * Remove a SNS (same name sibling) and verify that cached paths are
+ * adapted accordingly. The removed SNS's path is not cached.
+ */
+ public void testRemoveSNS() throws Exception {
+ StaticItemStateManager ism = new StaticItemStateManager();
+ cache = new CachingHierarchyManager(ism.getRootNodeId(), ism, null);
+ ism.setContainer(cache);
+ NodeState a = ism.addNode(ism.getRoot(), "a");
+ NodeState b1 = ism.addNode(a, "b");
+ NodeState b2 = ism.addNode(a, "b");
+ Path path = cache.getPath(b2.getNodeId());
+ assertEquals(toPath("/a/b[2]"), path);
+ ism.removeNode(b1);
+ path = cache.getPath(b2.getNodeId());
+ assertEquals(toPath("/a/b"), path);
+ }
+
+ /**
+ * Remove a SNS (same name sibling) and verify that cached paths are
+ * adapted accordingly. The removed SNS's path is cached.
+ */
+ public void testRemoveSNSWithCachedPath() throws Exception {
+ StaticItemStateManager ism = new StaticItemStateManager();
+ cache = new CachingHierarchyManager(ism.getRootNodeId(), ism, null);
+ ism.setContainer(cache);
+ NodeState a = ism.addNode(ism.getRoot(), "a");
+ NodeState b1 = ism.addNode(a, "b");
+ NodeState b2 = ism.addNode(a, "b");
+ cache.getPath(b1.getNodeId());
+ Path path = cache.getPath(b2.getNodeId());
+ assertEquals(toPath("/a/b[2]"), path);
+ ism.removeNode(b1);
+ path = cache.getPath(b2.getNodeId());
+ assertEquals(toPath("/a/b"), path);
}
/**
@@ -233,14 +323,14 @@
NodeState b1 = ism.addNode(a1, "b");
NodeState b2 = ism.addNode(a1, "b");
Path path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a1\t{}b", path.toString());
+ assertEquals(toPath("/a1/b"), path);
path = cache.getPath(b2.getNodeId());
- assertEquals("{}\t{}a1\t{}b[2]", path.toString());
+ assertEquals(toPath("/a1/b[2]"), path);
ism.renameNode(b1, "b1");
- assertTrue(cache.isCached(b1.getNodeId()));
- assertTrue(cache.isCached(b2.getNodeId()));
+ assertTrue(cache.isCached(b1.getNodeId(), null));
+ assertTrue(cache.isCached(b2.getNodeId(), null));
path = cache.getPath(b1.getNodeId());
- assertEquals("{}\t{}a1\t{}b1", path.toString());
+ assertEquals(toPath("/a1/b1"), path);
}
/**
@@ -506,7 +596,21 @@
* @return path
*/
private static Path toPath(String s) {
- return PathFactoryImpl.getInstance().create(s);
+ StringBuffer buf = new StringBuffer("{}");
+ int start = 1, length = s.length();
+ while (start < length) {
+ int end = s.indexOf('/', start);
+ if (end == -1) {
+ end = length;
+ }
+ String name = s.substring(start, end);
+ if (name.length() > 0) {
+ buf.append("\t{}");
+ buf.append(name);
+ }
+ start = end + 1;
+ }
+ return PathFactoryImpl.getInstance().create(buf.toString());
}
/**