blob: c6909bf44a3bea78d6c251189a0b9b39f163ca74 [file] [log] [blame]
/*
* 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.sling.ide.impl.vlt;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import org.apache.jackrabbit.vault.util.Text;
import org.apache.sling.ide.log.Logger;
import org.apache.sling.ide.transport.ResourceProxy;
/**
* The <tt>ReorderChildNodesCommand</tt> reorders the child nodes of the node matching the specified resource
*
*/
public class ReorderChildNodesCommand extends JcrCommand<Void> {
private final ResourceProxy resource;
public ReorderChildNodesCommand(Repository repository, Credentials credentials, ResourceProxy resource,
Logger logger) {
super(repository, credentials, resource.getPath(), logger);
this.resource = resource;
}
@Override
protected Void execute0(Session session) throws RepositoryException, IOException {
boolean nodeExists = session.nodeExists(getPath());
if (!nodeExists) {
return null;
}
Node node = session.getNode(getPath());
NodeType primaryNodeType = node.getPrimaryNodeType();
if (primaryNodeType.hasOrderableChildNodes()) {
reorderChildNodes(node, resource);
}
return null;
}
private void reorderChildNodes(Node nodeToReorder, ResourceProxy resourceToReorder) throws RepositoryException {
List<ResourceProxy> children = resourceToReorder.getChildren();
ListIterator<ResourceProxy> childrenIterator = children.listIterator();
// do not process
if (!childrenIterator.hasNext()) {
getLogger().trace("Resource at {0} has no children, skipping child node reordering",
resourceToReorder.getPath());
return;
}
Set<String> resourceChildNames = new HashSet<>(children.size());
Set<String> nodeChildNames = new HashSet<>(children.size());
List<Node> nodeChildren = new LinkedList<>();
NodeIterator nodeChildrenIt = nodeToReorder.getNodes();
while (nodeChildrenIt.hasNext()) {
Node node = nodeChildrenIt.nextNode();
nodeChildren.add(node);
nodeChildNames.add(node.getName());
}
for (ResourceProxy childResources : children) {
resourceChildNames.add(Text.getName(childResources.getPath()));
}
ListIterator<Node> nodeChildrenListIt = nodeChildren.listIterator();
// the sorting is conditioned on the local workspace and the repository having the same child names
// if that precondition is not met abort processing since there can be no meaningful result
traceResourcesAndNodes(children, nodeChildren);
if (! resourceChildNames.equals(nodeChildNames)) {
getLogger().warn(
"Different child names between the local workspace ( " + resourceChildNames
+ ") and the repository (" + nodeChildNames + ") for path " + resource.getPath()
+ ". Reordering will not be performed");
return;
}
while (childrenIterator.hasNext() || nodeChildrenListIt.hasNext()) {
ResourceProxy childResource = childrenIterator.next();
Node childNode = nodeChildrenListIt.next();
// order is as expected, skip reordering
if (Text.getName(childResource.getPath()).equals(childNode.getName())) {
// descend into covered child resources once they are properly arranged and perform reordering
if (resourceToReorder.covers(childResource.getPath())) {
reorderChildNodes(childNode, childResource);
}
continue;
}
// don't perform any reordering if this particular node does not have reorderable children
if (!nodeToReorder.getPrimaryNodeType().hasOrderableChildNodes()) {
getLogger().trace("Node at {0} does not have orderable child nodes, skipping reordering of {1}",
nodeToReorder.getPath(), childResource.getPath());
continue;
}
String expectedParentName;
if (childrenIterator.hasNext()) {
expectedParentName = Text.getName(childrenIterator.next().getPath());
childrenIterator.previous(); // move back
} else {
expectedParentName = null;
}
getLogger().trace("For node at {0} ordering {1} before {2}", nodeToReorder.getPath(),
Text.getName(childResource.getPath()), expectedParentName);
nodeToReorder.orderBefore(Text.getName(childResource.getPath()), expectedParentName);
}
}
private void traceResourcesAndNodes(List<ResourceProxy> children, List<Node> nodeChildren)
throws RepositoryException {
StringBuilder out = new StringBuilder();
out.append("Comparison of nodes and resources before reordering \n");
out.append(" === Resources === \n");
for (int i = 0; i < children.size(); i++) {
out.append(String.format("%3d. %s%n", i, children.get(i).getPath()));
}
out.append(" === Nodes === \n");
for (int i = 0; i < nodeChildren.size(); i++) {
out.append(String.format("%3d. %s%n", i, nodeChildren.get(i).getPath()));
}
getLogger().trace(out.toString());
}
@Override
public Kind getKind() {
return Kind.REORDER_CHILDREN;
}
}