| /* |
| * 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; |
| } |
| } |