You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2018/06/27 13:51:05 UTC

[2/2] james-project git commit: JAMES-2425 Do not leak protocol over webadmin

JAMES-2425 Do not leak protocol over webadmin


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/ee71575a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/ee71575a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/ee71575a

Branch: refs/heads/master
Commit: ee71575a69bd6f6817df90267719b7936a7ad0f5
Parents: c9f8c9c
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Fri Jun 15 15:19:36 2018 +0200
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Jun 27 15:50:05 2018 +0200

----------------------------------------------------------------------
 .../utils/InMemoryMailRepositoryStore.java      |  10 +
 .../utils/InMemoryMailRepositoryStoreTest.java  |  65 +++++
 .../MailRepositoryStoreBeanFactory.java         |  11 +
 .../mailrepository/api/MailRepositoryStore.java |  21 +-
 .../mock/MockMailRepositoryStore.java           |  10 +
 .../transport/mailets/DlpIntegrationTest.java   |   8 +-
 .../transport/mailets/ToRepositoryTest.java     |   4 +-
 .../mailrepository/mailrepository-api/pom.xml   |   5 +
 .../mailrepository/api/MailRepositoryPath.java  |  81 ++++++
 .../mailrepository/api/MailRepositoryUrl.java   |  38 ++-
 .../api/MailRepositoryUrlTest.java              |  40 ++-
 .../WebAdminServerIntegrationTest.java          |  16 +-
 .../dto/ExtendedMailRepositoryResponse.java     |  21 +-
 .../webadmin/dto/MailRepositoryResponse.java    |  19 +-
 .../dto/SingleMailRepositoryResponse.java       |  43 ++++
 .../webadmin/routes/MailRepositoriesRoutes.java | 111 ++++----
 .../service/ClearMailRepositoryTask.java        |  39 +--
 .../service/MailRepositoryStoreService.java     |  82 +++---
 .../service/ReprocessingAllMailsTask.java       |  22 +-
 .../service/ReprocessingOneMailTask.java        |  22 +-
 .../webadmin/service/ReprocessingService.java   |  21 +-
 .../routes/MailRepositoriesRoutesTest.java      | 255 ++++++++++---------
 .../service/MailRepositoryStoreServiceTest.java |  60 ++---
 src/site/markdown/server/manage-webadmin.md     |  80 +++---
 24 files changed, 714 insertions(+), 370 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/InMemoryMailRepositoryStore.java
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/InMemoryMailRepositoryStore.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/InMemoryMailRepositoryStore.java
index 06c2cf3..b93ea77 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/InMemoryMailRepositoryStore.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/InMemoryMailRepositoryStore.java
@@ -34,6 +34,7 @@ import org.apache.commons.configuration.DefaultConfigurationBuilder;
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
@@ -101,6 +102,15 @@ public class InMemoryMailRepositoryStore implements MailRepositoryStore, Configu
     }
 
     @Override
+    public Stream<MailRepository> getByPath(MailRepositoryPath path) {
+        return destinationToRepositoryAssociations
+                .keySet()
+                .stream()
+                .filter((MailRepositoryUrl key) -> key.getPath().equals(path))
+                .map(destinationToRepositoryAssociations::get);
+    }
+
+    @Override
     public MailRepository select(MailRepositoryUrl mailRepositoryUrl) {
         return Optional.ofNullable(destinationToRepositoryAssociations.get(mailRepositoryUrl))
             .orElseGet(Throwing.supplier(

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/container/guice/guice-common/src/test/java/org/apache/james/utils/InMemoryMailRepositoryStoreTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/src/test/java/org/apache/james/utils/InMemoryMailRepositoryStoreTest.java b/server/container/guice/guice-common/src/test/java/org/apache/james/utils/InMemoryMailRepositoryStoreTest.java
index f373bbe..5ad89e4 100644
--- a/server/container/guice/guice-common/src/test/java/org/apache/james/utils/InMemoryMailRepositoryStoreTest.java
+++ b/server/container/guice/guice-common/src/test/java/org/apache/james/utils/InMemoryMailRepositoryStoreTest.java
@@ -28,6 +28,7 @@ import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.file.FileMailRepository;
@@ -46,6 +47,8 @@ import com.google.common.collect.Sets;
 
 public class InMemoryMailRepositoryStoreTest {
     private static final MailRepositoryUrl FILE_REPO = MailRepositoryUrl.from("file://repo");
+    private static final MailRepositoryUrl MEMORY_REPO = MailRepositoryUrl.from("memory://repo");
+    private static final MailRepositoryPath PATH_REPO = MailRepositoryPath.from("repo");
 
     private MemoryMailRepositoryUrlStore urlStore;
 
@@ -150,6 +153,36 @@ public class InMemoryMailRepositoryStoreTest {
     }
 
     @Test
+    public void getPathsShouldBeEmptyIfNoSelectWerePerformed() {
+        assertThat(repositoryStore.getPaths()).isEmpty();
+    }
+
+    @Test
+    public void getPathsShouldReturnUsedUrls() {
+        MailRepositoryPath path1 = MailRepositoryPath.from("repo1");
+        MailRepositoryPath path2 = MailRepositoryPath.from("repo1");
+        MailRepositoryPath path3 = MailRepositoryPath.from("repo1");
+        repositoryStore.select(MailRepositoryUrl.fromPathAndProtocol(path1, "file"));
+        repositoryStore.select(MailRepositoryUrl.fromPathAndProtocol(path2, "file"));
+        repositoryStore.select(MailRepositoryUrl.fromPathAndProtocol(path3, "file"));
+        assertThat(repositoryStore.getPaths()).containsOnly(path1, path2, path3);
+    }
+
+    @Test
+    public void getPathsResultsShouldNotBeDuplicatedWithTheSameProtocol() {
+        repositoryStore.select(FILE_REPO);
+        repositoryStore.select(FILE_REPO);
+        assertThat(repositoryStore.getPaths()).containsExactly(PATH_REPO);
+    }
+
+    @Test
+    public void getPathsResultsShouldNotBeDuplicatedWithDifferentProtocols() {
+        repositoryStore.select(FILE_REPO);
+        repositoryStore.select(MEMORY_REPO);
+        assertThat(repositoryStore.getPaths()).containsExactly(PATH_REPO);
+    }
+
+    @Test
     public void getShouldReturnEmptyWhenUrlNotInUse() {
         assertThat(repositoryStore.get(FILE_REPO))
             .isEmpty();
@@ -172,6 +205,38 @@ public class InMemoryMailRepositoryStoreTest {
     }
 
     @Test
+    public void getByPathShouldReturnEmptyWhenUrlNotInUse() {
+        assertThat(repositoryStore.getByPath(PATH_REPO))
+            .isEmpty();
+    }
+
+    @Test
+    public void getByPathShouldReturnPreviouslyCreatedMatchingMailRepository() {
+        MailRepository mailRepository = repositoryStore.select(FILE_REPO);
+
+        assertThat(repositoryStore.getByPath(PATH_REPO))
+            .contains(mailRepository);
+    }
+
+    @Test
+    public void getByPathShouldReturnPreviouslyCreatedMatchingMailRepositories() {
+        MailRepository mailRepositoryFile = repositoryStore.select(FILE_REPO);
+        MailRepository mailRepositoryArbitrary = repositoryStore.select(MEMORY_REPO);
+
+        assertThat(repositoryStore.getByPath(PATH_REPO))
+            .contains(mailRepositoryFile)
+            .contains(mailRepositoryArbitrary);
+    }
+
+    @Test
+    public void getByPathShouldReturnEmptyWhenNoMailRepositoriesAreMatching() {
+        repositoryStore.select(FILE_REPO);
+
+        assertThat(repositoryStore.getByPath(MailRepositoryPath.from("unknown")))
+            .isEmpty();
+    }
+
+    @Test
     public void selectShouldNotReturnDifferentResultsWhenUsedInAConcurrentEnvironment() throws Exception {
         MailRepositoryUrl url = MailRepositoryUrl.from("memory://repo");
         int threadCount = 10;

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/container/spring/src/main/java/org/apache/james/container/spring/bean/factory/mailrepositorystore/MailRepositoryStoreBeanFactory.java
----------------------------------------------------------------------
diff --git a/server/container/spring/src/main/java/org/apache/james/container/spring/bean/factory/mailrepositorystore/MailRepositoryStoreBeanFactory.java b/server/container/spring/src/main/java/org/apache/james/container/spring/bean/factory/mailrepositorystore/MailRepositoryStoreBeanFactory.java
index a05b3ca..93deae5 100644
--- a/server/container/spring/src/main/java/org/apache/james/container/spring/bean/factory/mailrepositorystore/MailRepositoryStoreBeanFactory.java
+++ b/server/container/spring/src/main/java/org/apache/james/container/spring/bean/factory/mailrepositorystore/MailRepositoryStoreBeanFactory.java
@@ -34,6 +34,7 @@ import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.james.container.spring.bean.factory.AbstractBeanFactory;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.Protocol;
@@ -94,6 +95,16 @@ public class MailRepositoryStoreBeanFactory extends AbstractBeanFactory implemen
         return Optional.ofNullable(repositories.get(url));
     }
 
+    @Override
+    public Stream<MailRepository> getByPath(MailRepositoryPath path) {
+        return repositories
+                .keySet()
+                .stream()
+                .filter((MailRepositoryUrl key) -> key.getPath().equals(path))
+                .map(repositories::get);
+    }
+
+
     /**
      * <p>
      * Registers a new mail repository type in the mail store's registry based

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
----------------------------------------------------------------------
diff --git a/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java b/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
index 1ae2b5d..babc19c 100644
--- a/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
+++ b/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.mailrepository.api;
 
-import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -49,13 +48,27 @@ public interface MailRepositoryStore {
     Optional<MailRepository> get(MailRepositoryUrl url) throws MailRepositoryStoreException;
 
     /**
-     * Return a {@link List} which contains all urls of the selected
+     * Returns all the {@link MailRepository} for the given path.
+     */
+    Stream<MailRepository> getByPath(MailRepositoryPath path) throws MailRepositoryStoreException;
+
+    /**
+     * Return a {@link Stream} which contains all urls of the selected
      * {@link MailRepository}'s
-     * 
-     * @return urls
      */
     Stream<MailRepositoryUrl> getUrls();
 
+    /**
+     * Return a {@link Stream} which contains all paths of the selected
+     * {@link MailRepository}'s
+     */
+    default Stream<MailRepositoryPath> getPaths() {
+        return getUrls()
+            .map(MailRepositoryUrl::getPath)
+            .sorted()
+            .distinct();
+    }
+
     class MailRepositoryStoreException extends Exception {
         public MailRepositoryStoreException(String msg, Throwable t) {
             super(msg, t);

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/data/data-library/src/test/java/org/apache/james/mailrepository/mock/MockMailRepositoryStore.java
----------------------------------------------------------------------
diff --git a/server/data/data-library/src/test/java/org/apache/james/mailrepository/mock/MockMailRepositoryStore.java b/server/data/data-library/src/test/java/org/apache/james/mailrepository/mock/MockMailRepositoryStore.java
index dc3e1d9..6cd742e 100644
--- a/server/data/data-library/src/test/java/org/apache/james/mailrepository/mock/MockMailRepositoryStore.java
+++ b/server/data/data-library/src/test/java/org/apache/james/mailrepository/mock/MockMailRepositoryStore.java
@@ -25,6 +25,7 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 
@@ -47,6 +48,15 @@ public class MockMailRepositoryStore implements MailRepositoryStore {
     }
 
     @Override
+    public Stream<MailRepository> getByPath(MailRepositoryPath path) {
+        return storedObjectMap
+                .keySet()
+                .stream()
+                .filter((MailRepositoryUrl key) -> key.getPath().equals(path))
+                .map(storedObjectMap::get);
+    }
+
+    @Override
     public Stream<MailRepositoryUrl> getUrls() {
         return storedObjectMap.keySet().stream();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/DlpIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/DlpIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/DlpIntegrationTest.java
index 0762995..aae098e 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/DlpIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/DlpIntegrationTest.java
@@ -174,7 +174,7 @@ public class DlpIntegrationTest {
         MailRepositoryUrl repositoryUrl = MailRepositoryUrl.from(REPOSITORY_PREFIX + DEFAULT_DOMAIN);
         given()
             .spec(specification)
-        .get("/mailRepositories/" + repositoryUrl.urlEncoded() + "/mails")
+        .get("/mailRepositories/" + repositoryUrl.getPath().urlEncoded() + "/mails")
             .then()
             .statusCode(HttpStatus.NOT_FOUND_404);
     }
@@ -223,7 +223,8 @@ public class DlpIntegrationTest {
         MailRepositoryUrl repositoryUrl = MailRepositoryUrl.from(REPOSITORY_PREFIX + DEFAULT_DOMAIN);
         given()
             .spec(specification)
-            .put("/mailRepositories/" + repositoryUrl.urlEncoded());
+            .param("protocol", repositoryUrl.getProtocol().getValue())
+            .put("/mailRepositories/" + repositoryUrl.getPath().urlEncoded());
 
         given()
             .spec(specification)
@@ -253,8 +254,7 @@ public class DlpIntegrationTest {
         try {
             return given()
                 .spec(specification)
-                .get("/mailRepositories/" + repositoryUrl.urlEncoded() + "/mails")
-                .prettyPeek()
+            .get("/mailRepositories/" + repositoryUrl.getPath().urlEncoded() + "/mails")
                 .jsonPath()
                 .getList(".")
                 .size() == 1;

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToRepositoryTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToRepositoryTest.java
index 0fecd96..3bcff8c 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToRepositoryTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToRepositoryTest.java
@@ -117,7 +117,7 @@ public class ToRepositoryTest {
             .queryParam("processor", ProcessorConfiguration.STATE_TRANSPORT)
             .queryParam("action", "reprocess")
         .patch(MailRepositoriesRoutes.MAIL_REPOSITORIES
-                + "/" + CUSTOM_REPOSITORY.urlEncoded()
+                + "/" + CUSTOM_REPOSITORY.getPath().urlEncoded()
                 + "/mails")
             .jsonPath()
             .getString("taskId");
@@ -148,7 +148,7 @@ public class ToRepositoryTest {
             .queryParam("processor", ProcessorConfiguration.STATE_TRANSPORT)
             .queryParam("action", "reprocess")
             .patch(MailRepositoriesRoutes.MAIL_REPOSITORIES
-                + "/" + CUSTOM_REPOSITORY.urlEncoded()
+                + "/" + CUSTOM_REPOSITORY.getPath().urlEncoded()
                 + "/mails/" + key.asString())
             .jsonPath()
             .get("taskId");

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailrepository/mailrepository-api/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/pom.xml b/server/mailrepository/mailrepository-api/pom.xml
index cd972a7..e11f0c3 100644
--- a/server/mailrepository/mailrepository-api/pom.xml
+++ b/server/mailrepository/mailrepository-api/pom.xml
@@ -68,6 +68,11 @@
             <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-launcher</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryPath.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryPath.java b/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryPath.java
new file mode 100644
index 0000000..31d549d
--- /dev/null
+++ b/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryPath.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.james.mailrepository.api;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class MailRepositoryPath implements Comparable<MailRepositoryPath> {
+    public static final MailRepositoryPath fromEncoded(String encodedPath) throws UnsupportedEncodingException {
+        return new MailRepositoryPath(URLDecoder.decode(encodedPath, StandardCharsets.UTF_8.displayName()));
+    }
+
+    public static final MailRepositoryPath from(String path) {
+        return new MailRepositoryPath(path);
+    }
+
+    private final String value;
+
+    private MailRepositoryPath(String value) {
+        Preconditions.checkNotNull(value);
+        this.value = value;
+    }
+
+    public String asString() {
+        return value;
+    }
+
+    public String urlEncoded() throws UnsupportedEncodingException {
+        return URLEncoder.encode(value, StandardCharsets.UTF_8.displayName());
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof MailRepositoryPath) {
+            MailRepositoryPath that = (MailRepositoryPath) o;
+
+            return Objects.equals(this.value, that.value);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("value", value)
+            .toString();
+    }
+
+    @Override
+    public int compareTo(MailRepositoryPath that) {
+        return this.value.compareTo(that.value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryUrl.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryUrl.java b/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryUrl.java
index c6e69ec..f88ca2a 100644
--- a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryUrl.java
+++ b/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryUrl.java
@@ -23,37 +23,63 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 import java.util.Objects;
 
+import com.google.common.base.Joiner;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
 
 public class MailRepositoryUrl {
-    public static final MailRepositoryUrl fromEncoded(String encodedUrl) throws UnsupportedEncodingException {
+    private static final int PROTOCOL_PART = 0;
+    private static final String PROTOCOL_SEPARATOR = "://";
+    private static final int SKIP_PROTOCOL = 1;
+
+    public static MailRepositoryUrl fromEncoded(String encodedUrl) throws UnsupportedEncodingException {
         return new MailRepositoryUrl(URLDecoder.decode(encodedUrl, StandardCharsets.UTF_8.displayName()));
     }
 
-    public static final MailRepositoryUrl from(String url) {
+    public static MailRepositoryUrl from(String url) {
         return new MailRepositoryUrl(url);
     }
 
+    public static MailRepositoryUrl fromPathAndProtocol(MailRepositoryPath path, String protocol) {
+        return new MailRepositoryUrl(path, protocol);
+    }
+
     private final String value;
+    private final MailRepositoryPath path;
     private final Protocol protocol;
 
     private MailRepositoryUrl(String value) {
         Preconditions.checkNotNull(value);
-        Preconditions.checkArgument(value.contains(":"), "':' is mandatory to delimit protocol");
+        Preconditions.checkArgument(value.contains(PROTOCOL_SEPARATOR), "The expected format is: <protocol> \"" + PROTOCOL_SEPARATOR + "\" <path>");
         this.value = value;
-        this.protocol = new Protocol(Splitter.on(':')
-            .splitToList(value)
-            .get(0));
+        List<String> urlParts = Splitter.on(PROTOCOL_SEPARATOR).splitToList(value);
+        this.protocol = new Protocol(urlParts.get(PROTOCOL_PART));
+        this.path = MailRepositoryPath.from(
+            Joiner.on(PROTOCOL_SEPARATOR)
+                .join(Iterables.skip(urlParts, SKIP_PROTOCOL)));
+    }
+
+    private MailRepositoryUrl(MailRepositoryPath path, String protocol) {
+        Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(protocol);
+        this.path = path;
+        this.protocol = new Protocol(protocol);
+        this.value = protocol + PROTOCOL_SEPARATOR + path.asString();
     }
 
     public String asString() {
         return value;
     }
 
+    public MailRepositoryPath getPath() {
+        return path;
+    }
+
     public String urlEncoded() throws UnsupportedEncodingException {
         return URLEncoder.encode(value, StandardCharsets.UTF_8.displayName());
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/api/MailRepositoryUrlTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/api/MailRepositoryUrlTest.java b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/api/MailRepositoryUrlTest.java
index 83766b3..64a6d5e 100644
--- a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/api/MailRepositoryUrlTest.java
+++ b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/api/MailRepositoryUrlTest.java
@@ -28,45 +28,69 @@ import nl.jqno.equalsverifier.EqualsVerifier;
 
 public class MailRepositoryUrlTest {
     @Test
-    public void shouldMatchBeanContract() {
+    void shouldMatchBeanContract() {
         EqualsVerifier.forClass(MailRepositoryUrl.class)
-            .withIgnoredFields("protocol")
+            .withIgnoredFields("protocol", "path")
             .verify();
     }
 
     @Test
-    public void constructorShouldThrowWhenNull() {
+    void constructorShouldThrowWhenNull() {
         assertThatThrownBy(() -> MailRepositoryUrl.from(null))
             .isInstanceOf(NullPointerException.class);
     }
 
     @Test
-    public void constructorShouldThrowWhenNoSeparator() {
+    void constructorShouldThrowWhenNoSeparator() {
         assertThatThrownBy(() -> MailRepositoryUrl.from("invalid"))
             .isInstanceOf(IllegalArgumentException.class);
     }
 
     @Test
-    public void getProtocolShouldReturnValue() {
+    void getProtocolShouldReturnValue() {
         assertThat(MailRepositoryUrl.from("proto://abc").getProtocol())
             .isEqualTo(new Protocol("proto"));
     }
 
     @Test
-    public void getProtocolShouldReturnValueWhenEmpty() {
+    void getProtocolShouldReturnValueWhenEmpty() {
         assertThat(MailRepositoryUrl.from("://abc").getProtocol())
             .isEqualTo(new Protocol(""));
     }
 
     @Test
-    public void fromEncodedShouldReturnDecodedValue() throws Exception {
+    void fromEncodedShouldReturnDecodedValue() throws Exception {
         assertThat(MailRepositoryUrl.fromEncoded("url%3A%2F%2FmyRepo"))
             .isEqualTo(MailRepositoryUrl.from("url://myRepo"));
     }
 
     @Test
-    public void encodedValueShouldEncodeUnderlyingValue() throws Exception {
+    void fromPathAndProtocolShouldReturnTheFullValue() {
+        assertThat(MailRepositoryUrl.fromPathAndProtocol(MailRepositoryPath.from("myRepo"), "url"))
+            .isEqualTo(MailRepositoryUrl.from("url://myRepo"));
+    }
+
+    @Test
+    void encodedValueShouldEncodeUnderlyingValue() throws Exception {
         assertThat(MailRepositoryUrl.from("url://myRepo").urlEncoded())
             .isEqualTo("url%3A%2F%2FmyRepo");
     }
+
+    @Test
+    void getPathShouldReturnValue() {
+        assertThat(MailRepositoryUrl.from("proto://abc").getPath())
+            .isEqualTo(MailRepositoryPath.from("abc"));
+    }
+
+    @Test
+    void getPathShouldReturnValueWhenEmtpyPath() {
+        assertThat(MailRepositoryUrl.from("proto://").getPath())
+            .isEqualTo(MailRepositoryPath.from(""));
+    }
+
+    @Test
+    void getPathShouldReturnValueWhenSeveralProtocolSeparators() {
+        assertThat(MailRepositoryUrl.from("proto://abc://def").getPath())
+            .isEqualTo(MailRepositoryPath.from("abc://def"));
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index a0b5dde..b385f6f 100644
--- a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -119,10 +119,10 @@ public class WebAdminServerIntegrationTest {
         .then()
             .statusCode(HttpStatus.OK_200)
             .body("repository", containsInAnyOrder(
-                "file://var/mail/error/",
-                "file://var/mail/relay-denied/",
-                "file://var/mail/spam/",
-                "file://var/mail/address-error/"));
+                "var/mail/error/",
+                "var/mail/relay-denied/",
+                "var/mail/spam/",
+                "var/mail/address-error/"));
     }
 
     @Test
@@ -135,10 +135,10 @@ public class WebAdminServerIntegrationTest {
         .then()
             .statusCode(HttpStatus.OK_200)
             .body("repository", containsInAnyOrder(
-                "file://var/mail/error/",
-                "file://var/mail/relay-denied/",
-                "file://var/mail/spam/",
-                "file://var/mail/address-error/"));
+                "var/mail/error/",
+                "var/mail/relay-denied/",
+                "var/mail/spam/",
+                "var/mail/address-error/"));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/ExtendedMailRepositoryResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/ExtendedMailRepositoryResponse.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/ExtendedMailRepositoryResponse.java
index a1775a0..40e1dfa 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/ExtendedMailRepositoryResponse.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/ExtendedMailRepositoryResponse.java
@@ -19,17 +19,30 @@
 
 package org.apache.james.webadmin.dto;
 
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import java.io.UnsupportedEncodingException;
 
-public class ExtendedMailRepositoryResponse extends MailRepositoryResponse {
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 
+public class ExtendedMailRepositoryResponse implements MailRepositoryResponse {
+
+    private final MailRepositoryPath repository;
     private final long size;
 
-    public ExtendedMailRepositoryResponse(MailRepositoryUrl repository, long size) {
-        super(repository);
+    public ExtendedMailRepositoryResponse(MailRepositoryPath repository, long size) {
+        this.repository = repository;
         this.size = size;
     }
 
+    @Override
+    public String getRepository() {
+        return repository.asString();
+    }
+
+    @Override
+    public String getPath() throws UnsupportedEncodingException {
+        return repository.urlEncoded();
+    }
+
     public long getSize() {
         return size;
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailRepositoryResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailRepositoryResponse.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailRepositoryResponse.java
index 962ffa0..5cb3cd1 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailRepositoryResponse.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailRepositoryResponse.java
@@ -21,21 +21,10 @@ package org.apache.james.webadmin.dto;
 
 import java.io.UnsupportedEncodingException;
 
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
+public interface MailRepositoryResponse {
 
-public class MailRepositoryResponse {
+    String getRepository();
 
-    private final MailRepositoryUrl repository;
+    String getPath() throws UnsupportedEncodingException;
 
-    public MailRepositoryResponse(MailRepositoryUrl repository) {
-        this.repository = repository;
-    }
-
-    public String getRepository() {
-        return repository.asString();
-    }
-
-    public String getId() throws UnsupportedEncodingException {
-        return repository.urlEncoded();
-    }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/SingleMailRepositoryResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/SingleMailRepositoryResponse.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/SingleMailRepositoryResponse.java
new file mode 100644
index 0000000..eb2b5dd
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/SingleMailRepositoryResponse.java
@@ -0,0 +1,43 @@
+/****************************************************************
+ * 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.james.webadmin.dto;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.james.mailrepository.api.MailRepositoryPath;
+
+public class SingleMailRepositoryResponse implements MailRepositoryResponse {
+
+    private final MailRepositoryPath repository;
+
+    public SingleMailRepositoryResponse(MailRepositoryPath repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    public String getRepository() {
+        return repository.asString();
+    }
+
+    @Override
+    public String getPath() throws UnsupportedEncodingException {
+        return repository.urlEncoded();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
index c69f599..a6f9740 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
@@ -38,8 +38,8 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 
 import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskId;
@@ -122,17 +122,27 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     @PUT
-    @Path("/{encodedUrl}")
+    @Path("/{encodedPath}")
     @ApiOperation(value = "Create a repository")
+    @ApiImplicitParams({
+        @ApiImplicitParam(
+                required = true, 
+                dataType = "String", 
+                name = "protocol", 
+                paramType = "query",
+                example = "?protocol=file",
+                value = "Specify the storage protocol to use"),
+    })
     @ApiResponses(value = {
         @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The repository is created"),
         @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
     })
     public void definePutMailRepository() {
-        service.put(MAIL_REPOSITORIES + "/:encodedUrl", (request, response) -> {
-            MailRepositoryUrl url = decodedRepositoryUrl(request);
+        service.put(MAIL_REPOSITORIES + "/:encodedPath", (request, response) -> {
+            MailRepositoryPath path = decodedRepositoryPath(request);
+            String protocol = request.queryParams("protocol");
             try {
-                repositoryStoreService.createMailRepository(url);
+                repositoryStoreService.createMailRepository(path, protocol);
                 response.status(HttpStatus.NO_CONTENT_204);
                 return Constants.EMPTY_BODY;
             } catch (MailRepositoryStore.MailRepositoryStoreException e) {
@@ -140,14 +150,14 @@ public class MailRepositoriesRoutes implements Routes {
                     .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
                     .type(ErrorResponder.ErrorType.SERVER_ERROR)
                     .cause(e)
-                    .message(String.format("Error while creating a mail repository with url '%s'", url.asString()))
+                    .message(String.format("Error while creating a mail repository with path '%s' and protocol '%s'", path.asString(), protocol))
                     .haltError();
             }
         }, jsonTransformer);
     }
 
     @GET
-    @Path("/{encodedUrl}/mails")
+    @Path("/{encodedPath}/mails")
     @ApiOperation(value = "Listing all mails in a repository")
     @ApiImplicitParams({
         @ApiImplicitParam(
@@ -174,14 +184,13 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
     })
     public void defineListMails() {
-        service.get(MAIL_REPOSITORIES + "/:encodedUrl/mails", (request, response) -> {
+        service.get(MAIL_REPOSITORIES + "/:encodedPath/mails", (request, response) -> {
             Offset offset = ParametersExtractor.extractOffset(request);
             Limit limit = ParametersExtractor.extractLimit(request);
-            String encodedUrl = request.params("encodedUrl");
-            MailRepositoryUrl url = MailRepositoryUrl.fromEncoded(encodedUrl);
+            MailRepositoryPath path = decodedRepositoryPath(request);
             try {
-                return repositoryStoreService.listMails(url, offset, limit)
-                    .orElseThrow(() -> repositoryNotFound(encodedUrl, url));
+                return repositoryStoreService.listMails(path, offset, limit)
+                    .orElseThrow(() -> repositoryNotFound(request.params("encodedPath"), path));
 
             } catch (MailRepositoryStore.MailRepositoryStoreException | MessagingException e) {
                 throw ErrorResponder.builder()
@@ -202,13 +211,13 @@ public class MailRepositoriesRoutes implements Routes {
     })
     public void defineGetMailRepositories() {
         service.get(MAIL_REPOSITORIES,
-            (request, response) -> repositoryStoreService.listMailRepositories(),
+            (request, response) -> repositoryStoreService.listMailRepositories().collect(Guavate.toImmutableList()),
             jsonTransformer);
     }
 
     @GET
     @Produces("application/json, message/rfc822")
-    @Path("/{encodedUrl}/mails/{mailKey}")
+    @Path("/{encodedPath}/mails/{mailKey}")
     @ApiOperation(value = "Retrieving a specific mail details (this endpoint can accept both \"application/json\" or \"message/rfc822\")")
     @ApiResponses(value = {
         @ApiResponse(code = HttpStatus.OK_200, message = "The list of all mails in a repository", response = List.class),
@@ -216,15 +225,15 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "Not found - Could not retrieve the given mail.")
     })
     public void defineGetMail() {
-        service.get(MAIL_REPOSITORIES + "/:encodedUrl/mails/:mailKey", Constants.JSON_CONTENT_TYPE,
+        service.get(MAIL_REPOSITORIES + "/:encodedPath/mails/:mailKey", Constants.JSON_CONTENT_TYPE,
             (request, response) ->
-                getMailAsJson(decodedRepositoryUrl(request), new MailKey(request.params("mailKey")), request),
+                getMailAsJson(decodedRepositoryPath(request), new MailKey(request.params("mailKey")), request),
             jsonTransformer);
 
-        service.get(MAIL_REPOSITORIES + "/:encodedUrl/mails/:mailKey", Constants.RFC822_CONTENT_TYPE,
+        service.get(MAIL_REPOSITORIES + "/:encodedPath/mails/:mailKey", Constants.RFC822_CONTENT_TYPE,
             (request, response) -> writeMimeMessage(
                 getMailAsMimeMessage(
-                    decodedRepositoryUrl(request),
+                    decodedRepositoryPath(request),
                     new MailKey(request.params("mailKey"))),
                 response.raw()));
     }
@@ -242,18 +251,18 @@ public class MailRepositoriesRoutes implements Routes {
         return byteArrayOutputStream.size();
     }
 
-    private MimeMessage getMailAsMimeMessage(MailRepositoryUrl url, MailKey mailKey) {
+    private MimeMessage getMailAsMimeMessage(MailRepositoryPath path, MailKey mailKey) {
         try {
-            return repositoryStoreService.retrieveMessage(url, mailKey)
+            return repositoryStoreService.retrieveMessage(path, mailKey)
                 .orElseThrow(mailNotFoundError(mailKey));
         } catch (MailRepositoryStore.MailRepositoryStoreException | MessagingException e) {
             throw internalServerError(e);
         }
     }
 
-    private MailDto getMailAsJson(MailRepositoryUrl url, MailKey mailKey, Request request) {
+    private MailDto getMailAsJson(MailRepositoryPath path, MailKey mailKey, Request request) {
         try {
-            return repositoryStoreService.retrieveMail(url, mailKey, extractAdditionalFields(request.queryParamOrDefault("additionalFields", "")))
+            return repositoryStoreService.retrieveMail(path, mailKey, extractAdditionalFields(request.queryParamOrDefault("additionalFields", "")))
                 .orElseThrow(mailNotFoundError(mailKey));
         } catch (MailRepositoryStore.MailRepositoryStoreException | MessagingException e) {
             throw internalServerError(e);
@@ -290,11 +299,11 @@ public class MailRepositoriesRoutes implements Routes {
             .haltError();
     }
 
-    private HaltException repositoryNotFound(String encodedUrl, MailRepositoryUrl url) {
+    private HaltException repositoryNotFound(String encodedPath, MailRepositoryPath path) {
         return ErrorResponder.builder()
             .statusCode(HttpStatus.NOT_FOUND_404)
             .type(ErrorType.NOT_FOUND)
-            .message("The repository '" + encodedUrl + "' (decoded value: '" + url.asString() + "') does not exist")
+            .message("The repository '" + encodedPath + "' (decoded value: '" + path.asString() + "') does not exist")
             .haltError();
     }
 
@@ -308,7 +317,7 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     @GET
-    @Path("/{encodedUrl}")
+    @Path("/{encodedPath}")
     @ApiOperation(value = "Reading the information of a repository, such as size (can take some time to compute)")
     @ApiResponses(value = {
         @ApiResponse(code = HttpStatus.OK_200, message = "The repository information", response = List.class),
@@ -316,13 +325,12 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
     })
     public void defineGetMailRepository() {
-        service.get(MAIL_REPOSITORIES + "/:encodedUrl", (request, response) -> {
-            String encodedUrl = request.params("encodedUrl");
-            MailRepositoryUrl url = MailRepositoryUrl.fromEncoded(encodedUrl);
+        service.get(MAIL_REPOSITORIES + "/:encodedPath", (request, response) -> {
+            MailRepositoryPath path = decodedRepositoryPath(request);
             try {
-                long size = repositoryStoreService.size(url)
-                    .orElseThrow(() -> repositoryNotFound(encodedUrl, url));
-                return new ExtendedMailRepositoryResponse(url, size);
+                long size = repositoryStoreService.size(path)
+                    .orElseThrow(() -> repositoryNotFound(request.params("encodedPath"), path));
+                return new ExtendedMailRepositoryResponse(path, size);
             } catch (MailRepositoryStore.MailRepositoryStoreException e) {
                 throw ErrorResponder.builder()
                     .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
@@ -335,19 +343,19 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     @DELETE
-    @Path("/{encodedUrl}/mails/{mailKey}")
+    @Path("/{encodedPath}/mails/{mailKey}")
     @ApiOperation(value = "Deleting a specific mail from that mailRepository")
     @ApiResponses(value = {
         @ApiResponse(code = HttpStatus.OK_200, message = "Mail is no more stored in the repository", response = List.class),
         @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
     })
     public void defineDeleteMail() {
-        service.delete(MAIL_REPOSITORIES + "/:encodedUrl/mails/:mailKey", (request, response) -> {
-            MailRepositoryUrl url = decodedRepositoryUrl(request);
+        service.delete(MAIL_REPOSITORIES + "/:encodedPath/mails/:mailKey", (request, response) -> {
+            MailRepositoryPath path = decodedRepositoryPath(request);
             MailKey mailKey = new MailKey(request.params("mailKey"));
             try {
                 response.status(HttpStatus.NO_CONTENT_204);
-                repositoryStoreService.deleteMail(url, mailKey);
+                repositoryStoreService.deleteMail(path, mailKey);
                 return Constants.EMPTY_BODY;
             } catch (MailRepositoryStore.MailRepositoryStoreException | MessagingException e) {
                 throw ErrorResponder.builder()
@@ -361,7 +369,7 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     @DELETE
-    @Path("/{encodedUrl}/mails")
+    @Path("/{encodedPath}/mails")
     @ApiOperation(value = "Deleting all mails in that mailRepository")
     @ApiResponses(value = {
         @ApiResponse(code = HttpStatus.CREATED_201, message = "All mails are deleted", response = TaskIdDto.class),
@@ -369,10 +377,10 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - unknown action")
     })
     public void defineDeleteAll() {
-        service.delete(MAIL_REPOSITORIES + "/:encodedUrl/mails", (request, response) -> {
-            MailRepositoryUrl url = decodedRepositoryUrl(request);
+        service.delete(MAIL_REPOSITORIES + "/:encodedPath/mails", (request, response) -> {
+            MailRepositoryPath path = decodedRepositoryPath(request);
             try {
-                Task task = repositoryStoreService.createClearMailRepositoryTask(url);
+                Task task = repositoryStoreService.createClearMailRepositoryTask(path);
                 TaskId taskId = taskManager.submit(task);
                 return TaskIdDto.respond(response, taskId);
             } catch (MailRepositoryStore.MailRepositoryStoreException | MessagingException e) {
@@ -387,7 +395,7 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     @PATCH
-    @Path("/{encodedUrl}/mails")
+    @Path("/{encodedPath}/mails")
     @ApiOperation(value = "Reprocessing all mails in that mailRepository")
     @ApiImplicitParams({
         @ApiImplicitParam(
@@ -421,7 +429,7 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - unknown action")
     })
     public void defineReprocessAll() {
-        service.patch(MAIL_REPOSITORIES + "/:encodedUrl/mails", (request, response) -> {
+        service.patch(MAIL_REPOSITORIES + "/:encodedPath/mails", (request, response) -> {
             Task task = toAllMailReprocessingTask(request);
             TaskId taskId = taskManager.submit(task);
             return TaskIdDto.respond(response, taskId);
@@ -429,17 +437,17 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     private Task toAllMailReprocessingTask(Request request) throws UnsupportedEncodingException, MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        MailRepositoryUrl url = decodedRepositoryUrl(request);
+        MailRepositoryPath path = decodedRepositoryPath(request);
         enforceActionParameter(request);
         Optional<String> targetProcessor = Optional.ofNullable(request.queryParams("processor"));
         String targetQueue = Optional.ofNullable(request.queryParams("queue")).orElse(MailQueueFactory.SPOOL);
 
-        Long repositorySize = repositoryStoreService.size(url).orElse(0L);
-        return new ReprocessingAllMailsTask(reprocessingService, repositorySize, url, targetQueue, targetProcessor);
+        Long repositorySize = repositoryStoreService.size(path).orElse(0L);
+        return new ReprocessingAllMailsTask(reprocessingService, repositorySize, path, targetQueue, targetProcessor);
     }
 
     @PATCH
-    @Path("/{encodedUrl}/mails/{key}")
+    @Path("/{encodedPath}/mails/{key}")
     @ApiOperation(value = "Reprocessing a single mail in that mailRepository")
     @ApiImplicitParams({
         @ApiImplicitParam(
@@ -473,7 +481,7 @@ public class MailRepositoriesRoutes implements Routes {
         @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - unknown action")
     })
     public void defineReprocessOne() {
-        service.patch(MAIL_REPOSITORIES + "/:encodedUrl/mails/:key", (request, response) -> {
+        service.patch(MAIL_REPOSITORIES + "/:encodedPath/mails/:key", (request, response) -> {
             Task task = toOneMailReprocessingTask(request);
             TaskId taskId = taskManager.submit(task);
             return TaskIdDto.respond(response, taskId);
@@ -481,13 +489,13 @@ public class MailRepositoriesRoutes implements Routes {
     }
 
     private Task toOneMailReprocessingTask(Request request) throws UnsupportedEncodingException {
-        MailRepositoryUrl url = decodedRepositoryUrl(request);
+        MailRepositoryPath path = decodedRepositoryPath(request);
         MailKey key = new MailKey(request.params("key"));
         enforceActionParameter(request);
         Optional<String> targetProcessor = Optional.ofNullable(request.queryParams("processor"));
         String targetQueue = Optional.ofNullable(request.queryParams("queue")).orElse(MailQueueFactory.SPOOL);
 
-        return new ReprocessingOneMailTask(reprocessingService, url, targetQueue, key, targetProcessor);
+        return new ReprocessingOneMailTask(reprocessingService, path, targetQueue, key, targetProcessor);
     }
 
     private void enforceActionParameter(Request request) {
@@ -501,10 +509,6 @@ public class MailRepositoriesRoutes implements Routes {
         }
     }
 
-    private MailRepositoryUrl decodedRepositoryUrl(Request request) throws UnsupportedEncodingException {
-        return MailRepositoryUrl.fromEncoded(request.params("encodedUrl"));
-    }
-
     private Set<AdditionalField> extractAdditionalFields(String additionalFieldsParam) throws IllegalArgumentException {
         return Splitter
             .on(',')
@@ -516,4 +520,7 @@ public class MailRepositoriesRoutes implements Routes {
             .collect(Guavate.toImmutableSet());
     }
 
+    private MailRepositoryPath decodedRepositoryPath(Request request) throws UnsupportedEncodingException {
+        return MailRepositoryPath.fromEncoded(request.params("encodedPath"));
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ClearMailRepositoryTask.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ClearMailRepositoryTask.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ClearMailRepositoryTask.java
index 853e530..406330f 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ClearMailRepositoryTask.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ClearMailRepositoryTask.java
@@ -19,33 +19,36 @@
 
 package org.apache.james.webadmin.service;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Supplier;
 
 import javax.mail.MessagingException;
 
 import org.apache.james.mailrepository.api.MailRepository;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskExecutionDetails;
 
+import com.github.fge.lambdas.Throwing;
+
 public class ClearMailRepositoryTask implements Task {
 
     public static final String TYPE = "clearMailRepository";
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
-        private final MailRepositoryUrl repositoryUrl;
+        private final MailRepositoryPath repositoryPath;
         private final Supplier<Long> countSupplier;
         private final long initialCount;
 
-        public AdditionalInformation(MailRepositoryUrl repositoryUrl, Supplier<Long> countSupplier) {
-            this.repositoryUrl = repositoryUrl;
+        public AdditionalInformation(MailRepositoryPath repositoryPath, Supplier<Long> countSupplier) {
+            this.repositoryPath = repositoryPath;
             this.initialCount = countSupplier.get();
             this.countSupplier = countSupplier;
         }
 
-        public String getRepositoryUrl() {
-            return repositoryUrl.asString();
+        public String getRepositoryPath() {
+            return repositoryPath.asString();
         }
 
         public long getRemainingCount() {
@@ -57,18 +60,18 @@ public class ClearMailRepositoryTask implements Task {
         }
     }
 
-    private final MailRepository mailRepository;
+    private final List<MailRepository> mailRepositories;
     private final AdditionalInformation additionalInformation;
 
-    public ClearMailRepositoryTask(MailRepository mailRepository, MailRepositoryUrl url) {
-        this.mailRepository = mailRepository;
-        this.additionalInformation = new AdditionalInformation(url, this::getRemainingSize);
+    public ClearMailRepositoryTask(List<MailRepository> mailRepositories, MailRepositoryPath path) {
+        this.mailRepositories = mailRepositories;
+        this.additionalInformation = new AdditionalInformation(path, this::getRemainingSize);
     }
 
     @Override
     public Result run() {
         try {
-            mailRepository.removeAll();
+            removeAllInAllRepositories();
             return Result.COMPLETED;
         } catch (MessagingException e) {
             LOGGER.error("Encountered error while clearing repository", e);
@@ -76,6 +79,10 @@ public class ClearMailRepositoryTask implements Task {
         }
     }
 
+    private void removeAllInAllRepositories() throws MessagingException {
+        mailRepositories.forEach(Throwing.consumer(MailRepository::removeAll));
+    }
+
     @Override
     public String type() {
         return TYPE;
@@ -87,10 +94,10 @@ public class ClearMailRepositoryTask implements Task {
     }
 
     public long getRemainingSize() {
-        try {
-            return mailRepository.size();
-        } catch (MessagingException e) {
-            throw new RuntimeException(e);
-        }
+        return mailRepositories
+                .stream()
+                .map(Throwing.function(MailRepository::size).sneakyThrow())
+                .mapToLong(Long::valueOf)
+                .sum();
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
index 6efce69..ff4ee76 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
@@ -22,6 +22,8 @@ package org.apache.james.webadmin.service;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -29,6 +31,7 @@ import javax.mail.internet.MimeMessage;
 
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.task.Task;
@@ -39,7 +42,7 @@ import org.apache.james.webadmin.dto.InaccessibleFieldException;
 import org.apache.james.webadmin.dto.MailDto;
 import org.apache.james.webadmin.dto.MailDto.AdditionalField;
 import org.apache.james.webadmin.dto.MailKeyDTO;
-import org.apache.james.webadmin.dto.MailRepositoryResponse;
+import org.apache.james.webadmin.dto.SingleMailRepositoryResponse;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.mailet.Mail;
 import org.eclipse.jetty.http.HttpStatus;
@@ -56,56 +59,54 @@ public class MailRepositoryStoreService {
         this.mailRepositoryStore = mailRepositoryStore;
     }
 
-    public List<MailRepositoryResponse> listMailRepositories() {
-        return mailRepositoryStore.getUrls()
-            .map(MailRepositoryResponse::new)
-            .collect(Guavate.toImmutableList());
+    public Stream<SingleMailRepositoryResponse> listMailRepositories() {
+        return mailRepositoryStore
+            .getPaths()
+            .map(SingleMailRepositoryResponse::new);
     }
 
-    public MailRepository createMailRepository(MailRepositoryUrl repositoryUrl) throws MailRepositoryStore.MailRepositoryStoreException {
-        return mailRepositoryStore.create(repositoryUrl);
+    public MailRepository createMailRepository(MailRepositoryPath repositoryPath, String protocol) throws MailRepositoryStore.MailRepositoryStoreException {
+        return mailRepositoryStore.create(MailRepositoryUrl.fromPathAndProtocol(repositoryPath, protocol));
     }
 
-    public Optional<List<MailKeyDTO>> listMails(MailRepositoryUrl url, Offset offset, Limit limit) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        Optional<MailRepository> mailRepository = mailRepositoryStore.get(url);
-        ThrowingFunction<MailRepository, List<MailKeyDTO>> list = repository -> list(repository, offset, limit);
-        return mailRepository.map(Throwing.function(list).sneakyThrow());
+    public Optional<List<MailKeyDTO>> listMails(MailRepositoryPath path, Offset offset, Limit limit) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
+        ThrowingFunction<MailRepository, Stream<MailKeyDTO>> list = repository -> list(repository, offset, limit);
+        return Optional.of(getRepositories(path)
+                .flatMap(Throwing.function(list).sneakyThrow())
+                .collect(Guavate.toImmutableList()));
     }
 
-    private List<MailKeyDTO> list(MailRepository mailRepository, Offset offset, Limit limit) throws MessagingException {
+    private Stream<MailKeyDTO> list(MailRepository mailRepository, Offset offset, Limit limit) throws MessagingException {
         return limit.applyOnStream(
                 Iterators.toStream(mailRepository.list())
                     .skip(offset.getOffset()))
-                .map(MailKeyDTO::new)
-                .collect(Guavate.toImmutableList());
+                .map(MailKeyDTO::new);
     }
 
-    public Optional<Long> size(MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException {
-        Optional<MailRepository> mailRepository = mailRepositoryStore.get(url);
-        return mailRepository.map(Throwing.function(MailRepository::size).sneakyThrow());
+    public Optional<Long> size(MailRepositoryPath path) throws MailRepositoryStore.MailRepositoryStoreException {
+        return Optional.of(getRepositories(path)
+                .map(Throwing.function(MailRepository::size).sneakyThrow())
+                .mapToLong(Long::valueOf)
+                .sum());
     }
 
-    public Optional<MailDto> retrieveMail(MailRepositoryUrl url, MailKey mailKey, Set<AdditionalField> additionalAttributes) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException, InaccessibleFieldException {
-        MailRepository mailRepository = getRepository(url);
-
-        return Optional.ofNullable(mailRepository.retrieve(mailKey))
+    public Optional<MailDto> retrieveMail(MailRepositoryPath path, MailKey mailKey, Set<AdditionalField> additionalAttributes) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException, InaccessibleFieldException {
+        return fecthMail(path, mailKey)
             .map(Throwing.function((Mail mail) -> MailDto.fromMail(mail, additionalAttributes)).sneakyThrow());
     }
 
-    public Optional<MimeMessage> retrieveMessage(MailRepositoryUrl url, MailKey mailKey) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        MailRepository mailRepository = getRepository(url);
-
-        return Optional.ofNullable(mailRepository.retrieve(mailKey))
+    public Optional<MimeMessage> retrieveMessage(MailRepositoryPath path, MailKey mailKey) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
+        return fecthMail(path, mailKey)
             .map(Throwing.function(Mail::getMessage).sneakyThrow());
     }
 
-    public void deleteMail(MailRepositoryUrl url, MailKey mailKey) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        getRepository(url)
-            .remove(mailKey);
+    public void deleteMail(MailRepositoryPath path, MailKey mailKey) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
+        getRepositories(path)
+            .forEach(Throwing.consumer((MailRepository repository) -> repository.remove(mailKey)).sneakyThrow());
     }
 
-    public Task createClearMailRepositoryTask(MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        return new ClearMailRepositoryTask(getRepository(url), url);
+    public Task createClearMailRepositoryTask(MailRepositoryPath path) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
+        return new ClearMailRepositoryTask(getRepositories(path).collect(Guavate.toImmutableList()), path);
     }
 
     public MailRepository getRepository(MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException {
@@ -117,4 +118,25 @@ public class MailRepositoryStoreService {
                 .haltError());
     }
 
+    public Stream<MailRepository> getRepositories(MailRepositoryPath path) throws MailRepositoryStore.MailRepositoryStoreException {
+        Stream<MailRepository> byPath = mailRepositoryStore.getByPath(path);
+        List<MailRepository> repositories = byPath.collect(Collectors.toList());
+        if (repositories.isEmpty()) {
+            ErrorResponder.builder()
+                .statusCode(HttpStatus.NOT_FOUND_404)
+                .type(ErrorResponder.ErrorType.NOT_FOUND)
+                .message(path.asString() + " does not exist")
+                .haltError();
+        }
+
+        return repositories.stream();
+    }
+
+    private Optional<Mail> fecthMail(MailRepositoryPath path, MailKey mailKey) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
+        return getRepositories(path)
+                .map(Throwing.function((MailRepository repository) -> Optional.ofNullable(repository.retrieve(mailKey))).sneakyThrow())
+                .filter(Optional::isPresent)
+                .findFirst()
+                .orElse(Optional.empty());
+        }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingAllMailsTask.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingAllMailsTask.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingAllMailsTask.java
index 26ad50d..05b8ea1 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingAllMailsTask.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingAllMailsTask.java
@@ -25,8 +25,8 @@ import java.util.concurrent.atomic.AtomicLong;
 import javax.mail.MessagingException;
 
 import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskExecutionDetails;
 
@@ -37,14 +37,14 @@ public class ReprocessingAllMailsTask implements Task {
     public static final String TYPE = "reprocessingAllTask";
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
-        private final MailRepositoryUrl repositoryUrl;
+        private final MailRepositoryPath repositoryPath;
         private final String targetQueue;
         private final Optional<String> targetProcessor;
         private final long initialCount;
         private final AtomicLong processedCount;
 
-        public AdditionalInformation(MailRepositoryUrl repositoryUrl, String targetQueue, Optional<String> targetProcessor, long initialCount) {
-            this.repositoryUrl = repositoryUrl;
+        public AdditionalInformation(MailRepositoryPath repositoryPath, String targetQueue, Optional<String> targetProcessor, long initialCount) {
+            this.repositoryPath = repositoryPath;
             this.targetQueue = targetQueue;
             this.targetProcessor = targetProcessor;
             this.initialCount = initialCount;
@@ -59,8 +59,8 @@ public class ReprocessingAllMailsTask implements Task {
             return targetProcessor;
         }
 
-        public String getRepositoryUrl() {
-            return repositoryUrl.asString();
+        public String getRepositoryPath() {
+            return repositoryPath.asString();
         }
 
         public long getRemainingCount() {
@@ -78,25 +78,25 @@ public class ReprocessingAllMailsTask implements Task {
     }
 
     private final ReprocessingService reprocessingService;
-    private final MailRepositoryUrl repositoryUrl;
+    private final MailRepositoryPath repositoryPath;
     private final String targetQueue;
     private final Optional<String> targetProcessor;
     private final AdditionalInformation additionalInformation;
 
     public ReprocessingAllMailsTask(ReprocessingService reprocessingService, long repositorySize,
-                                    MailRepositoryUrl repositoryUrl, String targetQueue, Optional<String> targetProcessor) {
+                                    MailRepositoryPath repositoryPath, String targetQueue, Optional<String> targetProcessor) {
         this.reprocessingService = reprocessingService;
-        this.repositoryUrl = repositoryUrl;
+        this.repositoryPath = repositoryPath;
         this.targetQueue = targetQueue;
         this.targetProcessor = targetProcessor;
         this.additionalInformation = new AdditionalInformation(
-            repositoryUrl, targetQueue, targetProcessor, repositorySize);
+            repositoryPath, targetQueue, targetProcessor, repositorySize);
     }
 
     @Override
     public Result run() {
         try {
-            reprocessingService.reprocessAll(repositoryUrl, targetProcessor, targetQueue, additionalInformation::notifyProgress);
+            reprocessingService.reprocessAll(repositoryPath, targetProcessor, targetQueue, additionalInformation::notifyProgress);
             return Result.COMPLETED;
         } catch (MessagingException | MailRepositoryStore.MailRepositoryStoreException e) {
             LOGGER.error("Encountered error while reprocessing repository", e);

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingOneMailTask.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingOneMailTask.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingOneMailTask.java
index 453ff8b..550b59a 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingOneMailTask.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingOneMailTask.java
@@ -24,8 +24,8 @@ import java.util.Optional;
 import javax.mail.MessagingException;
 
 import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskExecutionDetails;
 
@@ -34,13 +34,13 @@ public class ReprocessingOneMailTask implements Task {
     public static final String TYPE = "reprocessingOneTask";
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
-        private final MailRepositoryUrl repositoryUrl;
+        private final MailRepositoryPath repositoryPath;
         private final String targetQueue;
         private final MailKey mailKey;
         private final Optional<String> targetProcessor;
 
-        public AdditionalInformation(MailRepositoryUrl repositoryUrl, String targetQueue, MailKey mailKey, Optional<String> targetProcessor) {
-            this.repositoryUrl = repositoryUrl;
+        public AdditionalInformation(MailRepositoryPath repositoryPath, String targetQueue, MailKey mailKey, Optional<String> targetProcessor) {
+            this.repositoryPath = repositoryPath;
             this.targetQueue = targetQueue;
             this.mailKey = mailKey;
             this.targetProcessor = targetProcessor;
@@ -58,32 +58,32 @@ public class ReprocessingOneMailTask implements Task {
             return targetProcessor;
         }
 
-        public String getRepositoryUrl() {
-            return repositoryUrl.asString();
+        public String getRepositoryPath() {
+            return repositoryPath.asString();
         }
     }
 
     private final ReprocessingService reprocessingService;
-    private final MailRepositoryUrl repositoryUrl;
+    private final MailRepositoryPath repositoryPath;
     private final String targetQueue;
     private final MailKey mailKey;
     private final Optional<String> targetProcessor;
     private final AdditionalInformation additionalInformation;
 
     public ReprocessingOneMailTask(ReprocessingService reprocessingService,
-                                   MailRepositoryUrl repositoryUrl, String targetQueue, MailKey mailKey, Optional<String> targetProcessor) {
+                                   MailRepositoryPath repositoryPath, String targetQueue, MailKey mailKey, Optional<String> targetProcessor) {
         this.reprocessingService = reprocessingService;
-        this.repositoryUrl = repositoryUrl;
+        this.repositoryPath = repositoryPath;
         this.targetQueue = targetQueue;
         this.mailKey = mailKey;
         this.targetProcessor = targetProcessor;
-        this.additionalInformation = new AdditionalInformation(repositoryUrl, targetQueue, mailKey, targetProcessor);
+        this.additionalInformation = new AdditionalInformation(repositoryPath, targetQueue, mailKey, targetProcessor);
     }
 
     @Override
     public Result run() {
         try {
-            reprocessingService.reprocess(repositoryUrl, mailKey, targetProcessor, targetQueue);
+            reprocessingService.reprocess(repositoryPath, mailKey, targetProcessor, targetQueue);
             return Result.COMPLETED;
         } catch (MessagingException | MailRepositoryStore.MailRepositoryStoreException e) {
             LOGGER.error("Encountered error while reprocessing repository", e);

http://git-wip-us.apache.org/repos/asf/james-project/blob/ee71575a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingService.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingService.java
index fbe68a4..f02bd3f 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingService.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/ReprocessingService.java
@@ -27,8 +27,8 @@ import javax.mail.MessagingException;
 
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.util.streams.Iterators;
@@ -48,20 +48,23 @@ public class ReprocessingService {
         this.mailRepositoryStoreService = mailRepositoryStoreService;
     }
 
-    public void reprocessAll(MailRepositoryUrl url, Optional<String> targetProcessor, String targetQueue, Consumer<MailKey> keyListener) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        MailRepository repository = mailRepositoryStoreService.getRepository(url);
+    public void reprocessAll(MailRepositoryPath path, Optional<String> targetProcessor, String targetQueue, Consumer<MailKey> keyListener) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
         MailQueue mailQueue = getMailQueue(targetQueue);
 
-        Iterators.toStream(repository.list())
-            .peek(keyListener)
-            .forEach(Throwing.consumer(key -> reprocess(repository, mailQueue, key, targetProcessor)));
+        mailRepositoryStoreService
+            .getRepositories(path)
+            .forEach(Throwing.consumer((MailRepository repository) ->
+                Iterators.toStream(repository.list())
+                    .peek(keyListener)
+                    .forEach(Throwing.consumer(key -> reprocess(repository, mailQueue, key, targetProcessor)))).sneakyThrow());
     }
 
-    public void reprocess(MailRepositoryUrl url, MailKey key, Optional<String> targetProcessor, String targetQueue) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
-        MailRepository repository = mailRepositoryStoreService.getRepository(url);
+    public void reprocess(MailRepositoryPath path, MailKey key, Optional<String> targetProcessor, String targetQueue) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
         MailQueue mailQueue = getMailQueue(targetQueue);
 
-        reprocess(repository, mailQueue, key, targetProcessor);
+        mailRepositoryStoreService
+            .getRepositories(path)
+            .forEach(Throwing.consumer((MailRepository repository) -> reprocess(repository, mailQueue, key, targetProcessor)).sneakyThrow());
     }
 
     private void reprocess(MailRepository repository, MailQueue mailQueue, MailKey key, Optional<String> targetProcessor) throws MessagingException {


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org