You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2020/07/13 09:39:05 UTC

[jackrabbit-filevault] branch feature/JCRVLT-449-edit-task created (now feabce2)

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a change to branch feature/JCRVLT-449-edit-task
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git.


      at feabce2  JCRVLT-449 add edit functionality

This branch includes the following new commits:

     new feabce2  JCRVLT-449 add edit functionality

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[jackrabbit-filevault] 01/01: JCRVLT-449 add edit functionality

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/JCRVLT-449-edit-task
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit feabce20805f883d0cb8ef6e28a48392687044f6
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Mon Jul 13 11:38:49 2020 +0200

    JCRVLT-449 add edit functionality
---
 vault-doc/src/site/markdown/rcp.md                 | 50 ++++++++++++++++++++++
 .../jackrabbit/vault/rcp/RcpTaskManager.java       |  9 +++-
 .../jackrabbit/vault/rcp/impl/RcpServlet.java      | 41 +++++++++++++-----
 .../jackrabbit/vault/rcp/impl/RcpTaskImpl.java     | 24 +++++++++--
 .../vault/rcp/impl/RcpTaskManagerImpl.java         | 16 ++++++-
 .../vault/rcp/impl/RcpTaskManagerImplTest.java     | 30 +++++++++++--
 vault-rcp/src/test/resources/edit_task.json        | 14 ++++++
 7 files changed, 164 insertions(+), 20 deletions(-)

diff --git a/vault-doc/src/site/markdown/rcp.md b/vault-doc/src/site/markdown/rcp.md
index a56c99c..7def6f6 100644
--- a/vault-doc/src/site/markdown/rcp.md
+++ b/vault-doc/src/site/markdown/rcp.md
@@ -180,6 +180,56 @@ Creates a new task.
         "status": "ok",
         "id": "test-id-1234"
     }
+#### Edit Task (POST)
+Edits an existing task. Almost al properties are optional. Unset properties are not modified!
+
+| Property     | Required | Comment |
+| ------------ | -------- | ------- |
+| cmd          | X  | Needs to be "**edit**". |
+| id           | X | Id of existing task. |
+| src          | \-  | URI of the remote source repository. |
+| srcCreds     | \- | Credentials to use for accessing the source repository in the format `<username>{:<password>}`. Alternatively put those in the URI given in `src`. |
+| dst          | \-  | Destination path in the local repository. |
+| batchsize    | \- | Size of batch until intermediate size. Default is 1024. |
+| recursive    | \- | **true** to descend recursively. Default is _false_. |
+| update       | \- | **true** to overwrite and/or delete existing nodes. Default is _false_. |
+| newer        | \- | **true** to respect _lastModified_ properties for update. Default is _false_. |
+| throttle     | \- | Number of seconds to sleep after each intermediate save. Default is _0_. |
+| resumeFrom   | \- | Source path to resume a prior aborted copy. Note that the algorithm simply skips all source nodes until the _resumeFrom_ path is found. It is necessary that the content structure of the source repository does not change in between runs, and that content already needs to be present in the detination location. |
+| excludes     | \- | Array of java regular expressions that exclude source paths. |
+| filter       | \- | Serialized [filter.xml](filter.html) specifing which repository areas to copy. Only used if `excludes` is not given. Make sure that the value is properly escaped. |
+
+
+##### Example
+    POST /system/jackrabbit/filevault/rcp HTTP/1.1
+    Host: localhost:4502
+    Content-Type: application/json
+    
+	{
+        "cmd":"edit",
+        "id":"test-id-1234",
+        "src":"http://admin:admin@localhost:4503/crx/-/jcr:root/content/geometrixx",
+        "dst":"/tmp/test1",
+        "batchsize": 2048,
+        "update": true,
+        "onlyNewer": false,
+        "recursive": true,
+        "throttle": 1,
+        "resumeFrom": "/content/geometrixx/fr",
+        "excludes": [
+            "/content/geometrixx/(en|fr)/tools(/.*)?"
+        ]
+    }
+
+    HTTP/1.1 200 OK
+    Content-Type: application/json;charset=utf-8
+    Location: /system/jackrabbit/filevault/rcp/test-id-1234
+    
+    {
+        "status": "ok",
+        "id": "test-id-1234"
+    }
+
     
 #### Set Task Credentials (POST)
 Sets credentials (or overwrites those) for an already existing task.
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
index 7509276..17d696d 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
@@ -24,6 +24,7 @@ import javax.jcr.Credentials;
 import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * {@code RcpTaskManager}...
@@ -36,11 +37,15 @@ public interface RcpTaskManager {
 
     boolean removeTask(String taskId);
 
-    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, WorkspaceFilter srcFilter, boolean recursive);
+    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, WorkspaceFilter srcFilter, @Nullable Boolean recursive);
 
-    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, boolean recursive)
+    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, @Nullable Boolean recursive)
             throws ConfigurationException;
 
     void setSourceCredentials(String taskId, Credentials srcCreds);
 
+    RcpTask editTask(String taskId, @Nullable RepositoryAddress src, @Nullable Credentials srcCreds, @Nullable String dst,
+            @Nullable List<String> excludes, @Nullable WorkspaceFilter srcFilter, @Nullable Boolean recursive)
+            throws ConfigurationException;
+
 }
\ No newline at end of file
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpServlet.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpServlet.java
index fae03a1..7870aa8 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpServlet.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpServlet.java
@@ -138,9 +138,10 @@ public class RcpServlet extends SlingAllMethodsServlet {
         final String id = data.optString(PARAM_ID, null);;
         try {
             // --------------------------------------------------------------------------------------------< create >---
-            if ("create".equals(cmd)) {
+            if ("create".equals(cmd) || "edit".equals(cmd)) {
+                boolean isEdit = "edit".equals(cmd);
                 String src = data.optString(PARAM_SRC, "");
-                if (src == null || src.length() == 0) {
+                if (isEdit && (src == null || src.length() == 0)) {
                     throw new IllegalArgumentException("Need src.");
                 }
                 String dst = data.optString(PARAM_DST, "");
@@ -158,14 +159,21 @@ public class RcpServlet extends SlingAllMethodsServlet {
                 if (srcCreds != null && srcCreds.length() > 0) {
                     creds = createCredentials(srcCreds);
                 }
-                boolean recursive = data.optBoolean(PARAM_RECURSIVE, false);
+                Boolean recursive = null;
+                if (data.has(PARAM_RECURSIVE)) {
+                    recursive = data.optBoolean(PARAM_RECURSIVE, false);
+                }
                 if (data.has(PARAM_EXCLUDES)) {
                     List<String> excludeList = new LinkedList<>();
                     JSONArray excludes = data.getJSONArray(PARAM_EXCLUDES);
                     for (int idx = 0; idx < excludes.length(); idx++) {
                         excludeList.add(excludes.getString(idx));
                     }
-                    task = taskMgr.addTask(address, creds, dst, id, excludeList, recursive);
+                    if (isEdit) {
+                        task = taskMgr.editTask(id, address, creds, dst, excludeList, null, recursive);
+                    } else {
+                        task = taskMgr.addTask(address, creds, dst, id, excludeList, recursive);
+                    }
                 } else {
                     final WorkspaceFilter filter;
                     if (data.has(PARAM_FILTER)) {
@@ -175,24 +183,37 @@ public class RcpServlet extends SlingAllMethodsServlet {
                     } else {
                         filter = null;
                     }
-                    task = taskMgr.addTask(address, creds, dst, id, filter, recursive);
+                    if (isEdit) {
+                        task = taskMgr.editTask(id, address, creds, dst, null, filter, recursive);
+                    } else {
+                        task = taskMgr.addTask(address, creds, dst, id, filter, recursive);
+                    }
                 }
 
                 // add additional data
                 if (data.has(PARAM_BATCHSIZE)) {
                     task.getRcp().setBatchSize((int) data.getLong(PARAM_BATCHSIZE));
                 }
-                task.getRcp().setUpdate(data.optBoolean(PARAM_UPDATE, false));
-                task.getRcp().setOnlyNewer(data.optBoolean(PARAM_ONLY_NEWER, false));
-                task.getRcp().setNoOrdering(data.optBoolean(PARAM_NO_ORDERING, false));
+                if (data.has(PARAM_UPDATE)) {
+                    task.getRcp().setUpdate(data.optBoolean(PARAM_UPDATE, false));
+                }
+                if (data.has(PARAM_ONLY_NEWER)) {
+                    task.getRcp().setOnlyNewer(data.optBoolean(PARAM_ONLY_NEWER, false));
+                }
+                if (data.has(PARAM_NO_ORDERING)) {
+                    task.getRcp().setNoOrdering(data.optBoolean(PARAM_NO_ORDERING, false));
+                }
                 if (data.has(PARAM_THROTTLE)) {
                     task.getRcp().setThrottle(data.getLong(PARAM_THROTTLE));
                 }
-                
                 if (data.has(PARAM_RESUME_FROM)) {
                     task.getRcp().setResumeFrom(data.getString(PARAM_RESUME_FROM));
                 }
-                response.setStatus(HttpServletResponse.SC_CREATED);
+                if (isEdit) {
+                    response.setStatus(HttpServletResponse.SC_OK);
+                } else {
+                    response.setStatus(HttpServletResponse.SC_CREATED);
+                }
                 String path = SERVLET_PATH + "/" + task.getId();
                 response.setHeader("Location", path);
 
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
index e8ac0e4..147d6df 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
@@ -36,6 +36,8 @@ import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.filter.DefaultPathFilter;
 import org.apache.jackrabbit.vault.rcp.RcpTask;
 import org.apache.jackrabbit.vault.util.RepositoryCopier;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -110,26 +112,42 @@ public class RcpTaskImpl implements Runnable, RcpTask {
     }
 
     public RcpTaskImpl(ClassLoader classLoader, RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes,
-            boolean recursive) throws ConfigurationException {
+            @Nullable Boolean recursive) throws ConfigurationException {
         this(classLoader, src, srcCreds, dst, id, createFilterForExcludes(excludes), recursive);
         this.excludes = excludes;
     }
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
     public RcpTaskImpl(@JsonProperty("classLoader") ClassLoader dynLoader, @JsonProperty("source") RepositoryAddress src, @JsonProperty("srcCreds") Credentials srcCreds, @JsonProperty("destination") String dst, @JsonProperty("id") String id, @JsonProperty("filter") WorkspaceFilter srcFilter,
-            @JsonProperty("recursive") boolean recursive) {
+            @JsonProperty("recursive") @Nullable Boolean recursive) {
         this.src = src;
         this.dst = dst;
         this.srcCreds = srcCreds;
         this.id = id == null || id.length() == 0
                 ? UUID.randomUUID().toString()
                 : id;
-        this.recursive = recursive;
+        this.recursive = recursive != null ? recursive : false;
         this.filter = srcFilter;
         initTransientData();
         this.classLoader = dynLoader;
     }
 
+    // additional constructor for editing existing tasks, all arguments are optional except the first one
+    public RcpTaskImpl(@NotNull RcpTaskImpl oldTask, @Nullable RepositoryAddress src, @Nullable Credentials srcCreds, @Nullable String dst, @Nullable List<String> excludes, @Nullable WorkspaceFilter srcFilter,
+            @Nullable Boolean recursive) {
+        this.src = src != null ? src : oldTask.src;
+        this.dst = dst != null ? dst : oldTask.dst;
+        this.srcCreds = srcCreds != null ? srcCreds : oldTask.srcCreds;
+        this.id = oldTask.id;
+        this.recursive = recursive != null ? recursive : oldTask.recursive;
+        this.excludes = excludes != null ? excludes : oldTask.excludes;
+        this.filter = srcFilter != null ? srcFilter : oldTask.filter;
+        // leave all other fields untouched
+        this.classLoader = oldTask.classLoader;
+        this.rcp = oldTask.rcp;
+        this.result = oldTask.result;
+    }
+
     private static WorkspaceFilter createFilterForExcludes(List<String> excludes) throws ConfigurationException {
         // could be done better
         DefaultWorkspaceFilter srcFilter = new DefaultWorkspaceFilter();
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
index 56572b0..cfd1dab 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
@@ -42,6 +42,7 @@ import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.rcp.RcpTask;
 import org.apache.jackrabbit.vault.rcp.RcpTaskManager;
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
+import org.jetbrains.annotations.Nullable;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -241,7 +242,7 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
     }
 
     @Override
-    public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, boolean recursive)
+    public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, @Nullable Boolean recursive)
             throws ConfigurationException {
         if (id != null && id.length() > 0 && tasks.containsKey(id)) {
             throw new IllegalArgumentException("Task with id " + id + " already exists.");
@@ -254,7 +255,7 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
 
     @Override
     public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, WorkspaceFilter srcFilter,
-            boolean recursive) {
+            @Nullable Boolean recursive) {
         if (id != null && id.length() > 0 && tasks.containsKey(id)) {
             throw new IllegalArgumentException("Task with id " + id + " already exists.");
         }
@@ -264,6 +265,17 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
         return task;
     }
 
+    
+    @Override
+    public RcpTask editTask(String taskId, @Nullable RepositoryAddress src, @Nullable Credentials srcCreds, @Nullable String dst, @Nullable List<String> excludes,
+            @Nullable WorkspaceFilter srcFilter, @Nullable Boolean recursive) throws ConfigurationException {
+        RcpTaskImpl oldTask = tasks.get(taskId);
+        if (oldTask == null) {
+            throw new IllegalArgumentException("No such task with id='" + taskId + "'");
+        }
+        return new RcpTaskImpl(oldTask, src, srcCreds, dst, excludes, srcFilter, recursive);
+    }
+
     @Override
     public boolean removeTask(String taskId) {
         RcpTask rcpTask = tasks.remove(taskId);
diff --git a/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java b/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
index c9661c8..8ad6ff3 100644
--- a/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
+++ b/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
@@ -38,9 +38,11 @@ import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
 import org.apache.jackrabbit.vault.rcp.RcpTask;
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.hamcrest.Description;
+import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;
 import org.hamcrest.collection.IsIterableContainingInOrder;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -75,11 +77,13 @@ public class RcpTaskManagerImplTest {
 
     Dictionary<String, Object> configProperties;
 
+    RcpTaskManagerImpl taskManager;
+
     @Rule
     public TemporaryFolder folder= new TemporaryFolder();
 
-    @Test
-    public void testSerializeDeserialize() throws IOException, ConfigurationException, URISyntaxException, RepositoryException {
+    @Before
+    public void before() throws IOException {
         Mockito.when(mockBundleContext.getDataFile(Mockito.anyString())).then(new Answer<File>() {
             @Override
             public File answer(InvocationOnMock invocation) throws Throwable {
@@ -98,7 +102,27 @@ public class RcpTaskManagerImplTest {
             }
             
         }).when(mockConfiguration).updateIfDifferent(Mockito.any());
-        RcpTaskManagerImpl taskManager = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin, Collections.emptyMap());
+        taskManager = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin, Collections.emptyMap());
+    }
+
+    @Test 
+    public void testEditTask() throws IOException, ConfigurationException, URISyntaxException {
+        DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
+        try (InputStream input = this.getClass().getResourceAsStream("/filter.xml")) {
+            filter.load(input);
+        }
+        RcpTaskImpl taskOld = (RcpTaskImpl)taskManager.addTask(new RepositoryAddress("http://localhost:4502"), new SimpleCredentials("testUser", "pw".toCharArray()), "/target/path", "2", Arrays.asList("exclude1", "exclude2"), false);
+        RcpTaskImpl taskNew = (RcpTaskImpl)taskManager.editTask(taskOld.getId(), null, null, null, null, null, null);
+        Assert.assertThat(taskNew, new TaskMatcher(taskOld));
+        
+        RepositoryAddress newSource = new RepositoryAddress("http://localhost:4503");
+        taskNew = (RcpTaskImpl)taskManager.editTask(taskOld.getId(), newSource, null, null, null, null, null);
+        Assert.assertThat(taskNew, Matchers.not(new TaskMatcher(taskOld)));
+        Assert.assertEquals(newSource, taskNew.getSource());
+    }
+
+    @Test
+    public void testSerializeDeserialize() throws IOException, ConfigurationException, URISyntaxException, RepositoryException {
         DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
         try (InputStream input = this.getClass().getResourceAsStream("/filter.xml")) {
             filter.load(input);
diff --git a/vault-rcp/src/test/resources/edit_task.json b/vault-rcp/src/test/resources/edit_task.json
new file mode 100644
index 0000000..066bb05
--- /dev/null
+++ b/vault-rcp/src/test/resources/edit_task.json
@@ -0,0 +1,14 @@
+{
+    "cmd":"edit",
+    "id":"copy-geometrixx",
+    "src":"http://admin:admin@localhost:4503/crx/-/jcr:root/content/geometrixx",
+    "dst":"/tmp/test_geo",
+    "batchsize": 2048,
+    "update": true,
+    "onlyNewer": true,
+    "recursive": true,
+    "throttle": 1,
+    "excludes": [
+        "/content/geometrixx/en/tools(/.*)?"
+    ]
+}