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/06/02 14:50:57 UTC

[jackrabbit-filevault] branch trunk updated: JCRVLT-438 add RCP API (#82)

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

kwin pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git


The following commit(s) were added to refs/heads/trunk by this push:
     new e538e8d  JCRVLT-438 add RCP API (#82)
e538e8d is described below

commit e538e8d9a702c943f6e0fc4b15a84087b423948c
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Tue Jun 2 16:50:29 2020 +0200

    JCRVLT-438 add RCP API (#82)
    
    * JCRVLT-438 add RCP API
---
 .../rcp/{impl/RcpTaskManager.java => RcpTask.java} |  44 ++++--
 .../vault/rcp/{impl => }/RcpTaskManager.java       |  12 +-
 .../jackrabbit/vault/rcp/impl/RcpServlet.java      |  76 +++++++---
 .../rcp/impl/{RcpTask.java => RcpTaskImpl.java}    | 166 +++++++++++----------
 .../vault/rcp/impl/RcpTaskManagerImpl.java         |  35 ++++-
 .../RcpTaskManager.java => package-info.java}      |  21 +--
 6 files changed, 216 insertions(+), 138 deletions(-)

diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTask.java
similarity index 50%
copy from vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
copy to vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTask.java
index 528b0f3..bc05654 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTask.java
@@ -14,23 +14,47 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.vault.rcp.impl;
+package org.apache.jackrabbit.vault.rcp;
 
-import java.util.Map;
+import java.util.List;
 
-import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 
 import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
+import org.apache.jackrabbit.vault.util.RepositoryCopier;
 
-/**
- * {@code RcpTaskManager}...
- */
-public interface RcpTaskManager {
+public interface RcpTask {
+
+    interface Result {
+        enum State {
+            NEW, RUNNING, ENDED, STOPPING, STOPPED
+        }
+
+        State getState();
+        /**
+         * 
+         * @return the exception in case of {@link #getState()} == ENDED and the execution was not successful otherwise {@code null}
+         */
+        Throwable getThrowable();
+    }
+
+    String getId();
+
+    RepositoryAddress getSource();
+
+    String getDestination();
+
+    boolean start(Session session) throws RepositoryException;
+
+    boolean stop();
+
+    RepositoryCopier getRcp();
 
-    RcpTask getTask(String taskId);
+    boolean isRecursive();
 
-    Map<String, RcpTask> getTasks();
+    Result getResult();
 
-    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id);
+    List<String> getExcludes();
 
 }
\ No newline at end of file
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
similarity index 70%
copy from vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
copy to vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
index 528b0f3..1e91987 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/RcpTaskManager.java
@@ -14,13 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.vault.rcp.impl;
+package org.apache.jackrabbit.vault.rcp;
 
+import java.util.List;
 import java.util.Map;
 
 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;
 
 /**
  * {@code RcpTaskManager}...
@@ -31,6 +34,11 @@ public interface RcpTaskManager {
 
     Map<String, RcpTask> getTasks();
 
-    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id);
+    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, List<String> excludes, 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 e2f66c1..7e15cde 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
@@ -19,6 +19,9 @@ package org.apache.jackrabbit.vault.rcp.impl;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 import javax.jcr.Credentials;
 import javax.jcr.Session;
@@ -29,6 +32,9 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
+import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
+import org.apache.jackrabbit.vault.rcp.RcpTask;
+import org.apache.jackrabbit.vault.rcp.RcpTaskManager;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.servlets.SlingAllMethodsServlet;
@@ -92,7 +98,7 @@ public class RcpServlet extends SlingAllMethodsServlet {
                 RcpTask task = taskMgr.getTask(taskId);
 
                 if (task != null) {
-                    task.write(w);
+                    write(w, task);
                 } else {
                     // return empty object
                     w.object().endObject();
@@ -101,7 +107,7 @@ public class RcpServlet extends SlingAllMethodsServlet {
                 w.object();
                 w.key("tasks").array();
                 for (RcpTask task: taskMgr.getTasks().values()) {
-                    task.write(w);
+                    write(w, task);
                 }
                 w.endArray();
                 w.endObject();
@@ -126,12 +132,15 @@ public class RcpServlet extends SlingAllMethodsServlet {
         }
         String cmd = data.optString(PARAM_CMD, "");
         RcpTask task;
+        final String id = data.optString(PARAM_ID, null);;
         try {
             // --------------------------------------------------------------------------------------------< create >---
             if ("create".equals(cmd)) {
                 String src = data.optString(PARAM_SRC, "");
+                if (src == null || src.length() == 0) {
+                    throw new IllegalArgumentException("Need src.");
+                }
                 String dst = data.optString(PARAM_DST, "");
-                String id = data.optString(PARAM_ID, null);
                 String srcCreds = data.optString(PARAM_SRC_CREDS, null);
 
                 RepositoryAddress address = new RepositoryAddress(src);
@@ -153,26 +162,29 @@ public class RcpServlet extends SlingAllMethodsServlet {
                                 srcCreds.substring(idx+1).toCharArray());
                     }
                 }
-
-                task = taskMgr.addTask(address, creds, dst, id);
+                boolean 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);
+                } else {
+                    task = taskMgr.addTask(address, creds, dst, id, (WorkspaceFilter)null, recursive);
+                }
 
                 // add additional data
                 if (data.has(PARAM_BATCHSIZE)) {
                     task.getRcp().setBatchSize((int) data.getLong(PARAM_BATCHSIZE));
                 }
-                task.setRecursive(data.optBoolean(PARAM_RECURSIVE, false));
                 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_THROTTLE)) {
                     task.getRcp().setThrottle(data.getLong(PARAM_THROTTLE));
                 }
-                if (data.has(PARAM_EXCLUDES)) {
-                    JSONArray excludes = data.getJSONArray(PARAM_EXCLUDES);
-                    for (int idx = 0; idx < excludes.length(); idx++) {
-                        task.addExclude(excludes.getString(idx));
-                    }
-                }
+                
                 if (data.has(PARAM_RESUME_FROM)) {
                     task.getRcp().setResumeFrom(data.getString(PARAM_RESUME_FROM));
                 }
@@ -182,7 +194,6 @@ public class RcpServlet extends SlingAllMethodsServlet {
 
             // ---------------------------------------------------------------------------------------------< start >---
             } else if ("start".equals(cmd)) {
-                String id = data.optString(PARAM_ID, null);
                 if (id == null || id.length() == 0) {
                     throw new IllegalArgumentException("Need task id.");
                 }
@@ -194,7 +205,6 @@ public class RcpServlet extends SlingAllMethodsServlet {
 
             // ----------------------------------------------------------------------------------------------< stop >---
             } else if ("stop".equals(cmd)) {
-                String id = data.optString(PARAM_ID, null);
                 if (id == null || id.length() == 0) {
                     throw new IllegalArgumentException("Need task id.");
                 }
@@ -206,15 +216,12 @@ public class RcpServlet extends SlingAllMethodsServlet {
 
             // --------------------------------------------------------------------------------------------< remove >---
             } else if ("remove".equals(cmd)) {
-                String id = data.optString(PARAM_ID, null);
                 if (id == null || id.length() == 0) {
                     throw new IllegalArgumentException("Need task id.");
                 }
-                task = taskMgr.getTasks().get(id);
-                if (task == null) {
+                if (!taskMgr.removeTask(id)) {
                     throw new IllegalArgumentException("No such task with id='" + id + "'");
                 }
-                task.remove();
 
             } else {
                 throw new IllegalArgumentException("Invalid command.");
@@ -226,7 +233,7 @@ public class RcpServlet extends SlingAllMethodsServlet {
             w.setTidy(true);
             w.object();
             w.key("status").value("ok");
-            w.key("id").value(task.getId());
+            w.key("id").value(id);
             w.endObject();
 
         } catch (Exception e) {
@@ -247,5 +254,36 @@ public class RcpServlet extends SlingAllMethodsServlet {
         }
     }
 
+    private static void write(JSONWriter w, RcpTask rcpTask) throws JSONException {
+        w.object();
+        w.key(RcpServlet.PARAM_ID).value(rcpTask.getId());
+        w.key(RcpServlet.PARAM_SRC).value(rcpTask.getSource().toString());
+        w.key(RcpServlet.PARAM_DST).value(rcpTask.getDestination());
+        w.key(RcpServlet.PARAM_RECURSIVE).value(rcpTask.isRecursive());
+        w.key(RcpServlet.PARAM_BATCHSIZE).value(rcpTask.getRcp().getBatchSize());
+        w.key(RcpServlet.PARAM_UPDATE).value(rcpTask.getRcp().isUpdate());
+        w.key(RcpServlet.PARAM_ONLY_NEWER).value(rcpTask.getRcp().isOnlyNewer());
+        w.key(RcpServlet.PARAM_NO_ORDERING).value(rcpTask.getRcp().isNoOrdering());
+        w.key(RcpServlet.PARAM_THROTTLE).value(rcpTask.getRcp().getThrottle());
+        w.key(RcpServlet.PARAM_RESUME_FROM).value(rcpTask.getRcp().getResumeFrom());
+        if (rcpTask.getExcludes().size() > 0) {
+            w.key(RcpServlet.PARAM_EXCLUDES).array();
+            for (String exclude: rcpTask.getExcludes()) {
+                w.value(exclude);
+            }
+            w.endArray();
+        }
+        w.key("status").object();
+        w.key(RcpServlet.PARAM_STATE).value(rcpTask.getResult().getState().name());
+        w.key("currentPath").value(rcpTask.getRcp().getCurrentPath());
+        w.key("lastSavedPath").value(rcpTask.getRcp().getLastKnownGood());
+        w.key("totalNodes").value(rcpTask.getRcp().getTotalNodes());
+        w.key("totalSize").value(rcpTask.getRcp().getTotalSize());
+        w.key("currentSize").value(rcpTask.getRcp().getCurrentSize());
+        w.key("currentNodes").value(rcpTask.getRcp().getCurrentNumNodes());
+        w.key("error").value(rcpTask.getResult().getThrowable() == null ? "" : rcpTask.getResult().getThrowable().toString());
+        w.endObject();
+        w.endObject();
+    }
 }
 
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTask.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
similarity index 68%
rename from vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTask.java
rename to vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
index 8194dbf..8a3c209 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTask.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskImpl.java
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.vault.rcp.impl;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -30,32 +29,25 @@ import org.apache.jackrabbit.vault.davex.DAVExRepositoryFactory;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
 import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
 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.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.apache.sling.commons.json.JSONException;
-import org.apache.sling.commons.json.io.JSONWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * {@code RcpTask}...
  */
-public class RcpTask implements Runnable {
+public class RcpTaskImpl implements Runnable, RcpTask {
 
     /**
      * default logger
      */
-    private static final Logger log = LoggerFactory.getLogger(RcpTask.class);
-
-    enum STATE {
-        NEW,
-        RUNNING,
-        ENDED,
-        STOPPING,
-        STOPPED
-    }
+    private static final Logger log = LoggerFactory.getLogger(RcpTaskImpl.class);
+
     private final RcpTaskManagerImpl mgr;
 
     private final String id;
@@ -68,21 +60,65 @@ public class RcpTask implements Runnable {
 
     private final String dst;
 
-    private boolean recursive;
-
-    private volatile STATE state = STATE.NEW;
+    private final boolean recursive;
 
-    private Exception error = null;
+    private volatile Result result;
 
-    private List<String> excludes = new ArrayList<String>();
+    private List<String> excludes;
 
     private Thread thread;
 
     private Session srcSession;
 
     private Session dstSession;
+    
+    private final static class ResultImpl implements RcpTask.Result {
+
+        private final State state;
+        private final Throwable throwable;
+
+        public ResultImpl(State state) {
+            this(state, null);
+        }
+        
+        public ResultImpl(State state, Throwable throwable) {
+            super();
+            this.state = state;
+            this.throwable = throwable;
+        }
+
+        @Override
+        public State getState() {
+            return state;
+        }
+
+        @Override
+        public Throwable getThrowable() {
+            return throwable;
+        }
+        
+    }
+
+    public RcpTaskImpl(RcpTaskManagerImpl mgr, RepositoryAddress src, Credentials srcCreds, String dst, String id) {
+        this(mgr, src, srcCreds, dst, id, (WorkspaceFilter)null, false);
+    }
+
+    public RcpTaskImpl(RcpTaskManagerImpl mgr, RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, boolean recursive) throws ConfigurationException {
+        this(mgr, src, srcCreds, dst, id, createFilterForExcludes(excludes), recursive);
+        this.excludes = excludes;
+    }
 
-    public RcpTask(RcpTaskManagerImpl mgr, RepositoryAddress src, Credentials srcCreds, String dst, String id) {
+    private static WorkspaceFilter createFilterForExcludes(List<String> excludes) throws ConfigurationException {
+        // could be done better
+        DefaultWorkspaceFilter srcFilter = new DefaultWorkspaceFilter();
+        PathFilterSet filterSet = new PathFilterSet("/");
+        for (String path: excludes) {
+            filterSet.addExclude(new DefaultPathFilter(path));
+        }
+        return srcFilter;
+    }
+
+    public RcpTaskImpl(RcpTaskManagerImpl mgr, RepositoryAddress src, Credentials srcCreds, String dst, String id, WorkspaceFilter srcFilter, boolean recursive) {
         this.mgr = mgr;
         this.src = src;
         this.dst = dst;
@@ -99,23 +135,31 @@ public class RcpTask implements Runnable {
                 log.error("{} {}", path, e.toString());
             }
         });
+        this.recursive = recursive;
+        if (srcFilter != null) {
+            rcp.setSourceFilter(srcFilter);
+        }
+        result = new ResultImpl(Result.State.NEW);
     }
 
+    @Override
     public String getId() {
         return id;
     }
 
+    @Override
     public RepositoryCopier getRcp() {
         return rcp;
     }
 
+    @Override
     public boolean stop() {
         // wait for thread
-        if (state != STATE.STOPPED && state != STATE.STOPPING) {
+        if (result.getState() != Result.State.STOPPED && result.getState() != Result.State.STOPPING) {
             rcp.abort();
             int cnt = 3;
             while (thread != null && thread.isAlive() && cnt-- > 0) {
-                state = STATE.STOPPING;
+                result = new ResultImpl(Result.State.STOPPING);
                 log.info("Stopping task {}...", id);
                 try {
                     thread.join(10000);
@@ -127,7 +171,7 @@ public class RcpTask implements Runnable {
                     thread.interrupt();
                 }
             }
-            state = STATE.STOPPED;
+            result = new ResultImpl(Result.State.STOPPED);
             thread = null;
             if (srcSession != null) {
                 srcSession.logout();
@@ -142,15 +186,10 @@ public class RcpTask implements Runnable {
         return true;
     }
 
-    public boolean remove() {
-        stop();
-        mgr.remove(this);
-        return true;
-    }
-
+    @Override
     public boolean start(Session session) throws RepositoryException {
-        if (state != STATE.NEW) {
-            throw new IllegalStateException("Unable to start task " + id + ". wrong state = " + state);
+        if (result.getState() != Result.State.NEW) {
+            throw new IllegalStateException("Unable to start task " + id + ". wrong state = " + result.getState());
         }
         // clone session
         dstSession = session.impersonate(new SimpleCredentials(session.getUserID(), new char[0]));
@@ -192,79 +231,42 @@ public class RcpTask implements Runnable {
     }
 
     public void run() {
-        state = STATE.RUNNING;
+        result = new ResultImpl(Result.State.RUNNING);
         log.info("Starting repository copy task id={}. From {} to {}.", new Object[]{
                 id, src.toString(), dst
         });
         try {
             rcp.copy(srcSession, src.getPath(), dstSession, dst, recursive);
-            state = STATE.ENDED;
-        } catch (Exception e) {
-            error = e;
-        } finally {
-            state = STATE.ENDED;
+            result = new ResultImpl(Result.State.ENDED);
+        } catch (Throwable e) {
+            result = new ResultImpl(Result.State.ENDED, e);
         }
         // todo: notify manager that we ended.
     }
 
-    public STATE getState() {
-        return state;
+    @Override
+    public Result getResult() {
+        return result;
     }
 
+    @Override
     public RepositoryAddress getSource() {
         return src;
     }
 
+    @Override
     public String getDestination() {
         return dst;
     }
 
-    public void setRecursive(boolean b) {
-        this.recursive = b;
+    @Override
+    public boolean isRecursive() {
+        return recursive;
     }
 
-    public void addExclude(String exclude) throws ConfigurationException {
-        excludes.add(exclude);
-        // could be done better
-        DefaultWorkspaceFilter srcFilter = new DefaultWorkspaceFilter();
-        PathFilterSet filterSet = new PathFilterSet("/");
-        for (String path: excludes) {
-            filterSet.addExclude(new DefaultPathFilter(path));
-        }
-        srcFilter.add(filterSet);
-        rcp.setSourceFilter(srcFilter);
-
+    @Override
+    public List<String> getExcludes() {
+        return excludes;
     }
 
-    public void write(JSONWriter w) throws JSONException {
-        w.object();
-        w.key(RcpServlet.PARAM_ID).value(id);
-        w.key(RcpServlet.PARAM_SRC).value(src.toString());
-        w.key(RcpServlet.PARAM_DST).value(dst);
-        w.key(RcpServlet.PARAM_RECURSIVE).value(recursive);
-        w.key(RcpServlet.PARAM_BATCHSIZE).value(rcp.getBatchSize());
-        w.key(RcpServlet.PARAM_UPDATE).value(rcp.isUpdate());
-        w.key(RcpServlet.PARAM_ONLY_NEWER).value(rcp.isOnlyNewer());
-        w.key(RcpServlet.PARAM_NO_ORDERING).value(rcp.isNoOrdering());
-        w.key(RcpServlet.PARAM_THROTTLE).value(rcp.getThrottle());
-        w.key(RcpServlet.PARAM_RESUME_FROM).value(rcp.getResumeFrom());
-        if (excludes.size() > 0) {
-            w.key(RcpServlet.PARAM_EXCLUDES).array();
-            for (String exclude: excludes) {
-                w.value(exclude);
-            }
-            w.endArray();
-        }
-        w.key("status").object();
-        w.key(RcpServlet.PARAM_STATE).value(state.name());
-        w.key("currentPath").value(rcp.getCurrentPath());
-        w.key("lastSavedPath").value(rcp.getLastKnownGood());
-        w.key("totalNodes").value(rcp.getTotalNodes());
-        w.key("totalSize").value(rcp.getTotalSize());
-        w.key("currentSize").value(rcp.getCurrentSize());
-        w.key("currentNodes").value(rcp.getCurrentNumNodes());
-        w.key("error").value(error == null ? "" : error.toString());
-        w.endObject();
-        w.endObject();
-    }
 }
\ No newline at end of file
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 e1d8692..ecd0870 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
@@ -18,11 +18,16 @@ package org.apache.jackrabbit.vault.rcp.impl;
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 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.apache.jackrabbit.vault.rcp.RcpTask;
+import org.apache.jackrabbit.vault.rcp.RcpTaskManager;
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -47,13 +52,13 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
     @Reference
     private DynamicClassLoaderManager dynLoaderMgr;
 
-    private final Map<String, RcpTask> tasks = new LinkedHashMap<String, RcpTask>();
+    private final Map<String, RcpTaskImpl> tasks = new LinkedHashMap<>();
 
     @Deactivate
     private void deactivate() {
         log.info("RcpTaskManager deactivated. Stopping running tasks...");
-        while (!tasks.isEmpty()) {
-            tasks.values().iterator().next().remove();
+        for (String id : tasks.keySet()) {
+            removeTask(id);
         }
         log.info("RcpTaskManager deactivated. Stopping running tasks...done.");
     }
@@ -65,18 +70,34 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
     public Map<String, RcpTask> getTasks() {
         return Collections.unmodifiableMap(tasks);
     }
+    
+    @Override
+    public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, List<String> excludes, boolean recursive) throws ConfigurationException {
+        if (id != null && id.length() > 0 && tasks.containsKey(id)) {
+            throw new IllegalArgumentException("Task with id " + id + " already exists.");
+        }
+        RcpTaskImpl task = new RcpTaskImpl(this, src, srcCreds, dst, id, excludes, recursive);
+        tasks.put(task.getId(), task);
+        return task;
+    }
 
-    public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id) {
+    @Override
+    public RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id, WorkspaceFilter srcFilter, boolean recursive) {
         if (id != null && id.length() > 0 && tasks.containsKey(id)) {
             throw new IllegalArgumentException("Task with id " + id + " already exists.");
         }
-        RcpTask task = new RcpTask(this, src, srcCreds, dst, id);
+        RcpTaskImpl task = new RcpTaskImpl(this, src, srcCreds, dst, id, srcFilter, recursive);
         tasks.put(task.getId(), task);
         return task;
     }
 
-    protected void remove(RcpTask task)  {
-        tasks.remove(task.getId());
+    public boolean removeTask(String taskId)  {
+        RcpTask rcpTask = tasks.remove(taskId);
+        if (rcpTask != null) {
+            rcpTask.stop();
+            return true;
+        }
+        return false;
     }
 
     protected ClassLoader getDynamicClassLoader() {
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/package-info.java
similarity index 66%
rename from vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
rename to vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/package-info.java
index 528b0f3..d887b62 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManager.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/package-info.java
@@ -14,23 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.vault.rcp.impl;
 
-import java.util.Map;
+@Version("1.0.0")
+package org.apache.jackrabbit.vault.rcp;
 
-import javax.jcr.Credentials;
-
-import org.apache.jackrabbit.vault.fs.api.RepositoryAddress;
-
-/**
- * {@code RcpTaskManager}...
- */
-public interface RcpTaskManager {
-
-    RcpTask getTask(String taskId);
-
-    Map<String, RcpTask> getTasks();
-
-    RcpTask addTask(RepositoryAddress src, Credentials srcCreds, String dst, String id);
-
-}
\ No newline at end of file
+import org.osgi.annotation.versioning.Version;
\ No newline at end of file