You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2014/07/17 16:44:21 UTC

svn commit: r1611371 - in /sling/trunk/tooling/ide: api-test/src/test/java/org/apache/sling/ide/serialization/ api/src/org/apache/sling/ide/transport/ eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ eclipse-test/src/org/apache/sling/ide/te...

Author: rombert
Date: Thu Jul 17 14:44:20 2014
New Revision: 1611371

URL: http://svn.apache.org/r1611371
Log:
SLING-3764 - Incorrect resource processing order - directory artifact
processed before primary artifact

- make sorting child nodes a separate command/step when processing
updates. This ensures that that the sorting is done at the end, when all
potential child node changes have been processed
- ensure that the resources returned from the SlingContentModuleFactory
are returned in a consistent order which allows us to process them in a
natural order form a vault serialization point of view

Added:
    sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java   (with props)
    sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java   (with props)
Modified:
    sling/trunk/tooling/ide/api-test/src/test/java/org/apache/sling/ide/serialization/StubRepository.java
    sling/trunk/tooling/ide/api/src/org/apache/sling/ide/transport/Repository.java
    sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ResourceChangeCommandFactory.java
    sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingContentModuleFactory.java
    sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingLaunchpadBehaviour.java
    sling/trunk/tooling/ide/impl-resource/src/org/apache/sling/ide/impl/resource/transport/RepositoryImpl.java
    sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/AddOrUpdateNodeCommand.java
    sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/VltRepository.java

Modified: sling/trunk/tooling/ide/api-test/src/test/java/org/apache/sling/ide/serialization/StubRepository.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/api-test/src/test/java/org/apache/sling/ide/serialization/StubRepository.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/api-test/src/test/java/org/apache/sling/ide/serialization/StubRepository.java (original)
+++ sling/trunk/tooling/ide/api-test/src/test/java/org/apache/sling/ide/serialization/StubRepository.java Thu Jul 17 14:44:20 2014
@@ -51,6 +51,11 @@ public class StubRepository implements R
     }
 
     @Override
+    public Command<Void> newReorderChildNodesCommand(ResourceProxy resourceProxy) {
+        return null;
+    }
+
+    @Override
     public RepositoryInfo getRepositoryInfo() {
         return null;
     }

Modified: sling/trunk/tooling/ide/api/src/org/apache/sling/ide/transport/Repository.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/api/src/org/apache/sling/ide/transport/Repository.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/api/src/org/apache/sling/ide/transport/Repository.java (original)
+++ sling/trunk/tooling/ide/api/src/org/apache/sling/ide/transport/Repository.java Thu Jul 17 14:44:20 2014
@@ -78,6 +78,19 @@ public interface Repository {
     RepositoryInfo getRepositoryInfo();
 
     Command<Void> newAddOrUpdateNodeCommand(FileInfo fileInfo, ResourceProxy resourceProxy);
+
+    /**
+     * Reorder the child nodes under the specified resource
+     * 
+     * <p>
+     * Only the first-level child nodes are typically ordered, but if child nodes are completely covered they will be
+     * ordered recursively.
+     * </p>
+     * 
+     * @param resourceProxy
+     * @return
+     */
+    Command<Void> newReorderChildNodesCommand(ResourceProxy resourceProxy);
 	
     Command<Void> newDeleteNodeCommand(String path);
  

Modified: sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ResourceChangeCommandFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ResourceChangeCommandFactory.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ResourceChangeCommandFactory.java (original)
+++ sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/ResourceChangeCommandFactory.java Thu Jul 17 14:44:20 2014
@@ -79,6 +79,17 @@ public class ResourceChangeCommandFactor
     private Command<?> addFileCommand(Repository repository, IResource resource) throws SerializationException,
             CoreException, IOException {
 
+        ResourceAndInfo rai = buildResourceAndInfo(repository, resource);
+        
+        if ( rai == null ) {
+            return null;
+        }
+
+        return repository.newAddOrUpdateNodeCommand(rai.getInfo(), rai.getResource());
+    }
+
+    private ResourceAndInfo buildResourceAndInfo(Repository repository, IResource resource) throws CoreException,
+            SerializationException, IOException {
         if (ignoredFileNames.contains(resource.getName())) {
             return null;
         }
@@ -102,6 +113,8 @@ public class ResourceChangeCommandFactor
 
         Filter filter = ProjectUtil.loadFilter(resource.getProject());
 
+        ResourceProxy resourceProxy = null;
+
         if (serializationManager.isSerializationFile(resource.getLocation().toOSString())) {
             InputStream contents = null;
             try {
@@ -109,7 +122,7 @@ public class ResourceChangeCommandFactor
                 contents = file.getContents();
                 String resourceLocation = file.getFullPath().makeRelativeTo(syncDirectory.getFullPath())
                         .toPortableString();
-                ResourceProxy resourceProxy = serializationManager.readSerializationData(resourceLocation, contents);
+                resourceProxy = serializationManager.readSerializationData(resourceLocation, contents);
                 // TODO - not sure if this 100% correct, but we definitely should not refer to the FileInfo as the
                 // .serialization file, since for nt:file/nt:resource nodes this will overwrite the file contents
                 String primaryType = (String) resourceProxy.getProperties().get(Repository.JCR_PRIMARY_TYPE);
@@ -130,11 +143,6 @@ public class ResourceChangeCommandFactor
 
                 }
 
-                if (isFiltered(filter, resourceProxy, repository, resource)) {
-                    return null;
-                }
-
-                return repository.newAddOrUpdateNodeCommand(info, resourceProxy);
             } catch (IOException e) {
                 Activator.getDefault().getPluginLogger().warn(e.getMessage(), e);
                 return null;
@@ -155,14 +163,14 @@ public class ResourceChangeCommandFactor
                 }
             }
 
-            ResourceProxy resourceProxy = buildResourceProxyForPlainFileOrFolder(resource, syncDirectory);
-
-            if (isFiltered(filter, resourceProxy, repository, resource)) {
-                return null;
-            }
+            resourceProxy = buildResourceProxyForPlainFileOrFolder(resource, syncDirectory);
+        }
 
-            return repository.newAddOrUpdateNodeCommand(info, resourceProxy);
+        if (isFiltered(filter, resourceProxy, repository, resource)) {
+            return null;
         }
+
+        return new ResourceAndInfo(resourceProxy, info);
     }
 
     private FileInfo createFileInfo(IResource resource, Repository repository) throws SerializationException,
@@ -405,4 +413,41 @@ public class ResourceChangeCommandFactor
         
         return repository.newDeleteNodeCommand(serializationManager.getRepositoryPath(resourceLocation));
     }
+
+    public Command<Void> newReorderChildNodesCommand(Repository repository, IResource res) throws CoreException {
+
+        try {
+            ResourceAndInfo rai = buildResourceAndInfo(repository, res);
+
+            if (rai == null) {
+                return null;
+            }
+
+            return repository.newReorderChildNodesCommand(rai.getResource());
+        } catch (SerializationException e) {
+            throw new CoreException(new Status(Status.ERROR, Activator.PLUGIN_ID, "Failed reordering child nodes for "
+                    + res, e));
+        } catch (IOException e) {
+            throw new CoreException(new Status(Status.ERROR, Activator.PLUGIN_ID, "Failed reordering child nodes for "
+                    + res, e));
+        }
+    }
+
+    private static class ResourceAndInfo {
+        private final ResourceProxy resource;
+        private final FileInfo info;
+
+        public ResourceAndInfo(ResourceProxy resource, FileInfo info) {
+            this.resource = resource;
+            this.info = info;
+        }
+
+        public ResourceProxy getResource() {
+            return resource;
+        }
+
+        public FileInfo getInfo() {
+            return info;
+        }
+    }
 }

Modified: sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingContentModuleFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingContentModuleFactory.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingContentModuleFactory.java (original)
+++ sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingContentModuleFactory.java Thu Jul 17 14:44:20 2014
@@ -17,6 +17,8 @@
 package org.apache.sling.ide.eclipse.core.internal;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import org.apache.sling.ide.eclipse.core.ProjectUtil;
@@ -27,13 +29,12 @@ import org.eclipse.core.resources.IResou
 import org.eclipse.core.resources.IResourceVisitor;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Status;
 import org.eclipse.wst.common.project.facet.core.IFacetedProject;
 import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
 import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
 import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.model.IModuleFile;
 import org.eclipse.wst.server.core.model.IModuleResource;
 import org.eclipse.wst.server.core.model.ModuleDelegate;
 import org.eclipse.wst.server.core.util.ModuleFile;
@@ -97,44 +98,27 @@ public class SlingContentModuleFactory e
     static class SlingContentModuleDelegate extends ProjectModule {
 
 
+        private static final IModuleResource[] EMPTY_MODULE_RESOURCES = new IModuleResource[0];
+
         public SlingContentModuleDelegate(IModule module) {
             super(module.getProject());
         }
 
         @Override
-        public IStatus validate() {
-            return Status.OK_STATUS; // TODO actually validate
-        }
-
-        @Override
         public IModuleResource[] members() throws CoreException {
             final List<IModuleResource> resources = new ArrayList<IModuleResource>();
-            final IFolder syncFolder = getProject().getFolder(ProjectUtil.getSyncDirectoryValue(getProject()));
+            final IFolder syncFolder = ProjectUtil.getSyncDirectory(getProject());
 
-            if (!syncFolder.exists()) {
-                return new IModuleResource[0];
+            if (syncFolder == null || !syncFolder.exists()) {
+                return EMPTY_MODULE_RESOURCES;
             }
 
-            getProject().accept(new IResourceVisitor() {
+            syncFolder.accept(new IResourceVisitor() {
                 @Override
                 public boolean visit(IResource resource) throws CoreException {
 
-                    if (resource.getType() == IResource.PROJECT) {
-                        return true;
-                    }
-
                     IPath relativePath = resource.getProjectRelativePath();
 
-                    if (relativePath.isPrefixOf(syncFolder.getProjectRelativePath())) {
-                        // parent directory of our sync location, don't process but recurse
-                        return true;
-                    }
-
-                    // unrelated resource tree, stop processing
-                    if (!syncFolder.getProjectRelativePath().isPrefixOf(relativePath)) {
-                        return false;
-                    }
-
                     IPath modulePath = relativePath.removeFirstSegments(syncFolder.getProjectRelativePath()
                             .segmentCount()); // remove sync dir
 
@@ -153,12 +137,55 @@ public class SlingContentModuleFactory e
                 }
             });
 
-            return resources.toArray(new IModuleResource[resources.size()]);
-        }
+            // sort files before folders in the same folder
+            // the reason is that we want to process .content.xml files before we
+            // descend down folders
+            Collections.sort(resources, new Comparator<IModuleResource>() {
 
-        @Override
-        public IModule[] getChildModules() {
-            return new IModule[0]; // TODO revisit, do we need child modules?
+                @Override
+                public int compare(IModuleResource o1, IModuleResource o2) {
+
+                    IPath p1 = o1.getModuleRelativePath();
+                    IPath p2 = o2.getModuleRelativePath();
+
+                    // shorter paths first
+                    if (p1.segmentCount() != p2.segmentCount()) {
+                        return p1.segmentCount() - p2.segmentCount();
+                    }
+
+                    // special-case the situation where they share a parent
+                    // to implement the 'files before folders' logic
+
+                    if (p1.removeLastSegments(1).equals(p2.removeLastSegments(1))) {
+
+                        if (o1.getClass() != o2.getClass()) {
+                            if (o1 instanceof IModuleFile) {
+                                return -1; // files first
+                            } else {
+                                return 1;
+                            }
+                        }
+
+                        return p1.segment(p1.segmentCount() - 1).compareTo(p2.segment(p2.segmentCount() - 1));
+                    }
+
+                    // find the first different segment path and return that
+                    for (int i = 0; i < p1.segmentCount(); i++) {
+                        String s1 = p1.segment(i);
+                        String s2 = p2.segment(i);
+
+                        int res = s1.compareTo(s2);
+
+                        if (res != 0) {
+                            return res;
+                        }
+                    }
+
+                    throw new IllegalArgumentException("Could not sort " + o1 + " and " + o2);
+                }
+            });
+
+            return resources.toArray(new IModuleResource[resources.size()]);
         }
     }
 }

Modified: sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingLaunchpadBehaviour.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingLaunchpadBehaviour.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingLaunchpadBehaviour.java (original)
+++ sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/core/internal/SlingLaunchpadBehaviour.java Thu Jul 17 14:44:20 2014
@@ -19,7 +19,9 @@ package org.apache.sling.ide.eclipse.cor
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import org.apache.sling.ide.artifacts.EmbeddedArtifactLocator;
 import org.apache.sling.ide.eclipse.core.ISlingLaunchpadServer;
@@ -339,6 +341,8 @@ public class SlingLaunchpadBehaviour ext
         // the behaviour for resources being filtered out is deletion, and that
         // would be an incorrect ( or at least suprising ) behaviour at development time
 
+        List<IModuleResource> addedOrUpdatedResources = new ArrayList<IModuleResource>();
+
         switch (deltaKind) {
             case ServerBehaviourDelegate.CHANGED:
                 for (IModuleResourceDelta resourceDelta : getPublishedResourceDelta(module)) {
@@ -372,6 +376,7 @@ public class SlingLaunchpadBehaviour ext
                         case IModuleResourceDelta.CHANGED:
                         case IModuleResourceDelta.NO_CHANGE: // TODO is this needed?
                             execute(addFileCommand(repository, resourceDelta.getModuleResource()));
+                            addedOrUpdatedResources.add(resourceDelta.getModuleResource());
                             break;
                         case IModuleResourceDelta.REMOVED:
                             execute(removeFileCommand(repository, resourceDelta.getModuleResource()));
@@ -384,16 +389,21 @@ public class SlingLaunchpadBehaviour ext
             case ServerBehaviourDelegate.NO_CHANGE: // TODO is this correct ?
                 for (IModuleResource resource : getResources(module)) {
                     execute(addFileCommand(repository, resource));
+                    addedOrUpdatedResources.add(resource);
                 }
                 break;
             case ServerBehaviourDelegate.REMOVED:
-                IModuleResource[] moduleResources2 = getResources(module);
-                for (IModuleResource resource : moduleResources2) {
+                for (IModuleResource resource : getResources(module)) {
                     execute(removeFileCommand(repository, resource));
                 }
                 break;
         }
 
+        // reorder the child nodes at the end, when all create/update/deletes have been processed
+        for (IModuleResource resource : addedOrUpdatedResources) {
+            execute(reorderChildNodesCommand(repository, resource));
+        }
+
 
         // set state to published
         super.publishModule(kind, deltaKind, module, monitor);
@@ -427,6 +437,18 @@ public class SlingLaunchpadBehaviour ext
         return commandFactory.newCommandForAddedOrUpdated(repository, res);
     }
 
+    private Command<?> reorderChildNodesCommand(Repository repository, IModuleResource resource) throws CoreException,
+            SerializationException, IOException {
+
+        IResource res = getResource(resource);
+
+        if (res == null) {
+            return null;
+        }
+
+        return commandFactory.newReorderChildNodesCommand(repository, res);
+    }
+
     private IResource getResource(IModuleResource resource) {
 
         IResource file = (IFile) resource.getAdapter(IFile.class);
@@ -447,7 +469,7 @@ public class SlingLaunchpadBehaviour ext
 
     private Command<?> removeFileCommand(Repository repository, IModuleResource resource)
             throws SerializationException, IOException, CoreException {
-    	
+
         IResource deletedResource = getResource(resource);
 
         if (deletedResource == null) {

Added: sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java?rev=1611371&view=auto
==============================================================================
--- sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java (added)
+++ sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java Thu Jul 17 14:44:20 2014
@@ -0,0 +1,127 @@
+/*
+ * 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.test.impl;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.sling.ide.eclipse.core.internal.SlingContentModuleFactory;
+import org.apache.sling.ide.test.impl.helpers.ProjectAdapter;
+import org.apache.sling.ide.test.impl.helpers.TemporaryProject;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.ServerUtil;
+import org.eclipse.wst.server.core.model.IModuleResource;
+import org.eclipse.wst.server.core.model.ModuleDelegate;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class SlingContentModuleAdapterTest {
+
+    @Rule
+    public TemporaryProject projectRule = new TemporaryProject();
+
+    @Test
+    public void projectMembersContainContentXmlFirst() throws Exception {
+
+        // create faceted project
+        IProject contentProject = projectRule.getProject();
+
+        ProjectAdapter project = new ProjectAdapter(contentProject);
+        project.addNatures(JavaCore.NATURE_ID, "org.eclipse.wst.common.project.facet.core.nature");
+
+        // install bundle facet
+        project.installFacet("sling.content", "1.0");
+
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/1_file.txt"), new ByteArrayInputStream(
+                new byte[0]));
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/2_folder/filler.txt"),
+                new ByteArrayInputStream(new byte[0]));
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/3_file.txt"), new ByteArrayInputStream(
+                new byte[0]));
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/4_folder/filler.txt"),
+                new ByteArrayInputStream(new byte[0]));
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/5_file.txt"), new ByteArrayInputStream(
+                new byte[0]));
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/.content.xml"), new ByteArrayInputStream(
+                new byte[0]));
+
+        IModule module = ServerUtil.getModule(contentProject);
+
+        SlingContentModuleFactory moduleFactory = new SlingContentModuleFactory();
+        ModuleDelegate moduleDelegate = moduleFactory.getModuleDelegate(module);
+
+        IModuleResource[] members = moduleDelegate.members();
+
+        assertThat("members[0].path", members[0].getModuleRelativePath().toPortableString(), equalTo(""));
+        assertThat("members[1].path", members[1].getModuleRelativePath().toPortableString(), equalTo("content"));
+        assertThat("members[2].path", members[2].getModuleRelativePath().toPortableString(),
+                equalTo("content/.content.xml"));
+    }
+
+    @Test
+    public void projectMembersContainDotDirFoldersLast() throws Exception {
+
+        // create faceted project
+        IProject contentProject = projectRule.getProject();
+
+        ProjectAdapter project = new ProjectAdapter(contentProject);
+        project.addNatures(JavaCore.NATURE_ID, "org.eclipse.wst.common.project.facet.core.nature");
+
+        // install bundle facet
+        project.installFacet("sling.content", "1.0");
+
+        project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/testproject/_jcr_content/image/file"),
+                new ByteArrayInputStream(new byte[0]));
+        project.createOrUpdateFile(
+                Path.fromPortableString("jcr_root/content/testproject/_jcr_content/image/file.dir/.content.xml"),
+                new ByteArrayInputStream(new byte[0]));
+        project.createOrUpdateFile(
+                Path.fromPortableString("jcr_root/content/testproject/_jcr_content/image/file.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_319.png"),
+                new ByteArrayInputStream(new byte[0]));
+
+        IModule module = ServerUtil.getModule(contentProject);
+
+        SlingContentModuleFactory moduleFactory = new SlingContentModuleFactory();
+        ModuleDelegate moduleDelegate = moduleFactory.getModuleDelegate(module);
+
+        IModuleResource[] members = moduleDelegate.members();
+        
+        int fileIdx = -1;
+        int fileDirIdx = -1;
+        
+        for (int i = 0; i < members.length; i++) {
+            String memberName = members[i].getModuleRelativePath().lastSegment();
+            if (memberName == null) {
+                continue;
+            } else if (memberName.equals("file.dir")) {
+                fileDirIdx = i;
+            } else if (memberName.equals("file")) {
+                fileIdx = i;
+            }
+        }
+
+        Assert.assertTrue("file not sorted before file.dir ; file index = " + fileIdx + ", file.dir index = "
+                + fileDirIdx, fileIdx < fileDirIdx);
+
+    }
+}

Propchange: sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/SlingContentModuleAdapterTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: sling/trunk/tooling/ide/impl-resource/src/org/apache/sling/ide/impl/resource/transport/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/impl-resource/src/org/apache/sling/ide/impl/resource/transport/RepositoryImpl.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/impl-resource/src/org/apache/sling/ide/impl/resource/transport/RepositoryImpl.java (original)
+++ sling/trunk/tooling/ide/impl-resource/src/org/apache/sling/ide/impl/resource/transport/RepositoryImpl.java Thu Jul 17 14:44:20 2014
@@ -23,6 +23,7 @@ import org.apache.sling.ide.transport.No
 import org.apache.sling.ide.transport.Repository;
 import org.apache.sling.ide.transport.RepositoryInfo;
 import org.apache.sling.ide.transport.ResourceProxy;
+import org.apache.sling.ide.transport.Result;
 import org.apache.sling.ide.transport.TracingCommand;
 import org.osgi.service.event.EventAdmin;
 
@@ -70,6 +71,17 @@ public class RepositoryImpl implements R
 	}
 
     @Override
+    public Command<Void> newReorderChildNodesCommand(ResourceProxy resourceProxy) {
+        return wrap(new AbstractCommand<Void>(repositoryInfo, httpClient, resourceProxy.getPath()) {
+            @Override
+            public Result<Void> execute() {
+                // TODO - this is a no-op
+                return null;
+            }
+        });
+    }
+
+    @Override
     public RepositoryInfo getRepositoryInfo() {
         return repositoryInfo;
     }

Modified: sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/AddOrUpdateNodeCommand.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/AddOrUpdateNodeCommand.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/AddOrUpdateNodeCommand.java (original)
+++ sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/AddOrUpdateNodeCommand.java Thu Jul 17 14:44:20 2014
@@ -33,9 +33,7 @@ import java.util.Arrays;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
@@ -112,12 +110,6 @@ public class AddOrUpdateNodeCommand exte
         if (primaryTypeHasChanged) {
             session.save();
         }
-
-        NodeType primaryNodeType = node.getPrimaryNodeType();
-
-        if (primaryNodeType.hasOrderableChildNodes()) {
-            reorderChildNodes(node, resource);
-        }
     }
 
     private void processDeletedNodes(Node node, ResourceProxy resource2) throws RepositoryException {
@@ -157,108 +149,6 @@ public class AddOrUpdateNodeCommand exte
         }
     }
 
-    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()) {
-            Activator.getDefault().getPluginLogger()
-                    .trace("Resource at {0} has no children, skipping child node reordering",
-                            resourceToReorder.getPath());
-            return;
-        }
-        List<Node> nodeChildren = new LinkedList<Node>();
-        NodeIterator nodeChildrenIt = nodeToReorder.getNodes();
-        while (nodeChildrenIt.hasNext()) {
-            nodeChildren.add(nodeChildrenIt.nextNode());
-        }
-        ListIterator<Node> nodeChildrenListIt = nodeChildren.listIterator();
-
-        // it is possible for the repository and the local workspace to have a different types of elements
-        // for instance if the repository has been changed independently of the local workspace modifications
-        // therefore allow for the
-        boolean changed = false;
-
-        traceResourcesAndNodes(children, nodeChildren);
-
-        if (children.size() != nodeChildren.size()) {
-            Activator.getDefault().getPluginLogger()
-                    .warn("Different number of children between the local workspace and the repository for path "
-                            + resourceToReorder.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()) {
-                Activator
-                        .getDefault()
-                        .getPluginLogger()
-                        .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;
-            }
-
-            Activator.getDefault().getPluginLogger()
-                    .trace("For node at {0} ordering {1} before {2}", nodeToReorder.getPath(),
-                            Text.getName(childResource.getPath()),
-                            expectedParentName);
-
-            nodeToReorder.orderBefore(Text.getName(childResource.getPath()), expectedParentName);
-            changed = true;
-            break;
-        }
-
-        // re-read the data and run the ordering again
-        // this makes sure that we don't have inconsistent data in the node list
-        if (changed) {
-            reorderChildNodes(nodeToReorder, resourceToReorder);
-        }
-
-    }
-
-    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()));
-        }
-
-        Activator.getDefault().getPluginLogger().trace(out.toString());
-    }
-
     private Node createNode(ResourceProxy resource, Session session) throws RepositoryException, FileNotFoundException {
 
         String parentLocation = Text.getRelativeParent(resource.getPath(), 1);

Added: sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java?rev=1611371&view=auto
==============================================================================
--- sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java (added)
+++ sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java Thu Jul 17 14:44:20 2014
@@ -0,0 +1,187 @@
+/*
+ * 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.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) {
+        super(repository, credentials, resource.getPath());
+
+        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()) {
+            Activator
+                    .getDefault()
+                    .getPluginLogger()
+                    .trace("Resource at {0} has no children, skipping child node reordering",
+                            resourceToReorder.getPath());
+            return;
+        }
+
+        Set<String> resourceChildNames = new HashSet<String>(children.size());
+        Set<String> nodeChildNames = new HashSet<String>(children.size());
+
+        List<Node> nodeChildren = new LinkedList<Node>();
+        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();
+
+        // it is possible for the repository and the local workspace to have a different types of elements
+        // for instance if the repository has been changed independently of the local workspace modifications
+        // therefore allow for the
+        boolean changed = false;
+
+        traceResourcesAndNodes(children, nodeChildren);
+
+        if (children.size() != nodeChildren.size()) {
+            Activator
+                    .getDefault()
+                    .getPluginLogger()
+                    .warn("Different number of children between the local workspace and the repository for path "
+                            + resourceToReorder.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()) {
+                Activator
+                        .getDefault()
+                        .getPluginLogger()
+                        .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;
+            }
+
+            Activator
+                    .getDefault()
+                    .getPluginLogger()
+                    .trace("For node at {0} ordering {1} before {2}", nodeToReorder.getPath(),
+                            Text.getName(childResource.getPath()), expectedParentName);
+
+            nodeToReorder.orderBefore(Text.getName(childResource.getPath()), expectedParentName);
+            changed = true;
+            break;
+        }
+
+        // re-read the data and run the ordering again
+        // this makes sure that we don't have inconsistent data in the node list
+        if (changed) {
+            reorderChildNodes(nodeToReorder, resourceToReorder);
+        }
+
+    }
+
+    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()));
+        }
+
+        Activator.getDefault().getPluginLogger().trace(out.toString());
+    }
+
+}

Propchange: sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/ReorderChildNodesCommand.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/VltRepository.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/VltRepository.java?rev=1611371&r1=1611370&r2=1611371&view=diff
==============================================================================
--- sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/VltRepository.java (original)
+++ sling/trunk/tooling/ide/impl-vlt/src/org/apache/sling/ide/impl/vlt/VltRepository.java Thu Jul 17 14:44:20 2014
@@ -87,6 +87,11 @@ public class VltRepository implements Re
     }
 
     @Override
+    public Command<Void> newReorderChildNodesCommand(ResourceProxy resource) {
+        return TracingCommand.wrap(new ReorderChildNodesCommand(jcrRepo, credentials, resource), eventAdmin);
+    }
+
+    @Override
     public Command<Void> newDeleteNodeCommand(String path) {
         return TracingCommand.wrap(new DeleteNodeCommand(jcrRepo, credentials, path), eventAdmin);
     }