SLING-7975 support ordering of resources (#18)
diff --git a/pom.xml b/pom.xml
index ef4c393..feebd5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -145,7 +145,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.18.2</version>
+ <version>2.23.7-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
index e40afb6..163ccba 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
@@ -34,6 +34,7 @@
import org.jetbrains.annotations.NotNull;
import javax.jcr.Item;
import javax.jcr.Node;
+import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -479,6 +480,44 @@
}
@Override
+ public boolean orderBefore(@NotNull ResolveContext<JcrProviderState> ctx, @NotNull Resource parent, @NotNull String name,
+ @Nullable String followingSiblingName) throws PersistenceException {
+ Node node = parent.adaptTo(Node.class);
+ if (node == null) {
+ throw new PersistenceException("The resource " + parent.getPath() + " cannot be adapted to Node. It is probably not provided by the JcrResourceProvider");
+ }
+ try {
+ // check if reordering necessary
+ NodeIterator nodeIterator = node.getNodes();
+ long existingNodePosition = -1;
+ long index = 0;
+ while (nodeIterator.hasNext()) {
+ Node childNode = nodeIterator.nextNode();
+ if (childNode.getName().equals(name)) {
+ existingNodePosition = index;
+ }
+ if (existingNodePosition >= 0) {
+ // is existing resource already at the desired position?
+ if (childNode.getName().equals(followingSiblingName)) {
+ if (existingNodePosition == index-1) {
+ return false;
+ }
+ }
+ // is the existing node already the last one in the list?
+ else if (followingSiblingName == null && existingNodePosition == nodeIterator.getSize()-1) {
+ return false;
+ }
+ }
+ index++;
+ }
+ node.orderBefore(name, followingSiblingName);
+ return true;
+ } catch (final RepositoryException e) {
+ throw new PersistenceException("Unable to reorder children below " + parent.getPath(), e, parent.getPath(), null);
+ }
+ }
+
+ @Override
public void delete(final @NotNull ResolveContext<JcrProviderState> ctx, final @NotNull Resource resource)
throws PersistenceException {
// try to adapt to Item
diff --git a/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java b/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
index b7641bc..684ce80 100644
--- a/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
+++ b/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
@@ -20,10 +20,17 @@
import java.security.Principal;
+import javax.jcr.Node;
import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceContext;
import org.junit.Assert;
import org.mockito.Mockito;
import org.osgi.framework.ServiceReference;
@@ -57,6 +64,42 @@
Mockito.when(ctx.getProviderState()).thenReturn(new JcrProviderState(session, null, false));
Assert.assertNotNull(jcrResourceProvider.adaptTo(ctx, Principal.class));
}
+
+ public void testOrderBefore() throws RepositoryException, PersistenceException {
+ Node parentNode = session.getRootNode().addNode("parent", NodeType.NT_UNSTRUCTURED);
+ parentNode.addNode("child1", NodeType.NT_UNSTRUCTURED);
+ parentNode.addNode("child2", NodeType.NT_UNSTRUCTURED);
+ parentNode.addNode("child3", NodeType.NT_UNSTRUCTURED);
+ session.save();
+
+ ResolveContext ctx = Mockito.mock(ResolveContext.class);
+ JcrProviderState state = new JcrProviderState(session, null, false);
+ Mockito.when(ctx.getProviderState()).thenReturn(state);
+ Resource parent = jcrResourceProvider.getResource(ctx, "/parent", ResourceContext.EMPTY_CONTEXT, null);
+ Assert.assertNotNull(parent);
+ // order with invalid names
+ try {
+ jcrResourceProvider.orderBefore(ctx, parent, "child3", "child4");
+ } catch (PersistenceException e) {
+ // expected
+ }
+ // order successfully
+ Assert.assertTrue(jcrResourceProvider.orderBefore(ctx, parent, "child2", "child1"));
+
+ // order already established
+ Assert.assertFalse(jcrResourceProvider.orderBefore(ctx, parent, "child2", "child1"));
+
+ // order child2 at end
+ Assert.assertTrue(jcrResourceProvider.orderBefore(ctx, parent, "child2", null));
+
+ // order child2 at end again
+ Assert.assertFalse(jcrResourceProvider.orderBefore(ctx, parent, "child2", null));
+
+ // make sure nothing is persisted until save
+ jcrResourceProvider.revert(ctx);
+
+ Assert.assertTrue(jcrResourceProvider.orderBefore(ctx, parent, "child2", null));
+ }
}