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 ad...@apache.org on 2016/04/04 16:28:11 UTC
[4/4] james-project git commit: JAMES-1712 Implement SetMailboxes:
create
JAMES-1712 Implement SetMailboxes: create
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/68ab6176
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/68ab6176
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/68ab6176
Branch: refs/heads/master
Commit: 68ab61763d954d8b0d38015649c1fa63d8b0082d
Parents: 166ee8f
Author: Antoine Duprat <an...@gmail.com>
Authored: Thu Mar 31 11:22:28 2016 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Mon Apr 4 16:27:12 2016 +0200
----------------------------------------------------------------------
.../integration/SetMailboxesMethodTest.java | 428 ++++++++++++++++++-
.../jmap/exceptions/MailboxNameException.java | 27 ++
.../MailboxParentNotFoundException.java | 34 ++
.../methods/SetMailboxesCreationProcessor.java | 124 +++++-
.../james/jmap/methods/SetMailboxesMethod.java | 2 +-
.../jmap/methods/SetMailboxesProcessor.java | 3 +-
.../org/apache/james/jmap/model/SetError.java | 17 +
.../james/jmap/model/SetMailboxesResponse.java | 25 +-
.../jmap/utils/CollectionHierarchySorter.java | 64 ---
.../utils/SortingHierarchicalCollections.java | 64 +++
.../SetMailboxesCreationProcessorTest.java | 71 +++
.../jmap/methods/SetMailboxesMethodTest.java | 2 +-
.../utils/CollectionHierarchySorterTest.java | 140 ------
.../SortingHierarchicalCollectionsTest.java | 140 ++++++
14 files changed, 924 insertions(+), 217 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
index 162bb6e..176ec06 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
@@ -20,14 +20,22 @@
package org.apache.james.jmap.methods.integration;
import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.with;
import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.JmapAuthentication;
import org.apache.james.jmap.api.access.AccessToken;
+import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +64,7 @@ public abstract class SetMailboxesMethodTest {
jmapServer.start();
RestAssured.port = jmapServer.getJmapPort();
RestAssured.config = newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8));
+ RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
username = "username@" + USERS_DOMAIN;
String password = "password";
@@ -71,9 +80,69 @@ public abstract class SetMailboxesMethodTest {
public void teardown() {
jmapServer.stop();
}
-
+
@Test
- public void setMailboxesShouldCreateMailbox() throws Exception {
+ public void setMailboxesShouldErrorNotSupportedWhenRoleGiven() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"," +
+ " \"role\" : \"Inbox\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", equalTo("Not yet implemented"));
+ }
+
+ @Test
+ public void setMailboxesShouldErrorNotSupportedWhenSortOrderGiven() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"," +
+ " \"sortOrder\" : 11" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", equalTo("Not yet implemented"));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnCreatedMailbox() throws Exception {
String requestBody =
"[" +
" [ \"setMailboxes\"," +
@@ -100,4 +169,359 @@ public abstract class SetMailboxesMethodTest {
.body(NAME, equalTo("mailboxesSet"))
.body(ARGUMENTS + ".created", hasKey("create-id01"));
}
+
+ @Test
+ public void setMailboxesShouldCreateMailbox() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ with()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .then()
+ .post("/jmap");
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body("[[\"getMailboxes\", {}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(ARGUMENTS + ".list", hasSize(2))
+ .body(ARGUMENTS + ".list.name", hasItems("foo"));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnCreatedMailboxWhenChildOfInboxMailbox() throws Exception {
+ String inboxId =
+ with()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body("[[\"getMailboxes\", {}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .extract()
+ .jsonPath()
+ .getString(ARGUMENTS + ".list[0].id");
+
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"," +
+ " \"parentId\" : \"" + inboxId + "\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".created", aMapWithSize(1))
+ .body(ARGUMENTS + ".created", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("parentId"), equalTo(inboxId)),
+ hasEntry(equalTo("name"), equalTo("foo")))));
+ }
+
+ @Test
+ public void setMailboxesShouldCreateMailboxWhenChildOfInboxMailbox() throws Exception {
+ String inboxId =
+ with()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body("[[\"getMailboxes\", {}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .extract()
+ .jsonPath()
+ .getString(ARGUMENTS + ".list[0].id");
+
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"," +
+ " \"parentId\" : \"" + inboxId + "\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap");
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body("[[\"getMailboxes\", {}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(ARGUMENTS + ".list", hasSize(2))
+ .body(ARGUMENTS + ".list.name", hasItems("foo"));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnNotCreatedWhenInvalidParentId() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"foo\"," +
+ " \"parentId\" : \"123\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(1))
+ .body(ARGUMENTS + ".notCreated", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("type"), equalTo("invalidArguments")),
+ hasEntry(equalTo("description"), equalTo("The parent mailbox '123' was not found.")))));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnCreatedMailboxWhenCreatingParentThenChildMailboxes() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id00\" : {" +
+ " \"name\" : \"parent\"" +
+ " }," +
+ " \"create-id01\" : {" +
+ " \"name\" : \"child\"," +
+ " \"parentId\" : \"create-id00\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".created", aMapWithSize(2))
+ .body(ARGUMENTS + ".created", hasEntry(equalTo("create-id00"), Matchers.allOf(
+ hasEntry(equalTo("parentId"), isEmptyOrNullString()),
+ hasEntry(equalTo("name"), equalTo("parent")))))
+ .body(ARGUMENTS + ".created", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("parentId"), not(isEmptyOrNullString())),
+ hasEntry(equalTo("name"), equalTo("child")))));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnCreatedMailboxWhenCreatingChildThenParentMailboxes() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"child\"," +
+ " \"parentId\" : \"create-id00\"" +
+ " }," +
+ " \"create-id00\" : {" +
+ " \"name\" : \"parent\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".created", aMapWithSize(2))
+ .body(ARGUMENTS + ".created", hasEntry(equalTo("create-id00"), Matchers.allOf(
+ hasEntry(equalTo("parentId"), isEmptyOrNullString()),
+ hasEntry(equalTo("name"), equalTo("parent")))))
+ .body(ARGUMENTS + ".created", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("parentId"), not(isEmptyOrNullString())),
+ hasEntry(equalTo("name"), equalTo("child")))));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnNotCreatedWhenMailboxAlreadyExists() throws Exception {
+ jmapServer.serverProbe().createMailbox("#private", username, "myBox");
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"myBox\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(1))
+ .body(ARGUMENTS + ".notCreated", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("type"), equalTo("invalidArguments")),
+ hasEntry(equalTo("description"), equalTo("The mailbox 'create-id01' already exists.")))));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnNotCreatedWhenCycleDetected() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"A\"," +
+ " \"parentId\" : \"create-id02\"" +
+ " }," +
+ " \"create-id02\" : {" +
+ " \"name\" : \"B\"," +
+ " \"parentId\" : \"create-id01\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(2))
+ .body(ARGUMENTS + ".notCreated", Matchers.allOf(
+ hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("type"), equalTo("invalidArguments")),
+ hasEntry(equalTo("description"), equalTo("The created mailboxes introduce a cycle.")))),
+ hasEntry(equalTo("create-id02"), Matchers.allOf(
+ hasEntry(equalTo("type"), equalTo("invalidArguments")),
+ hasEntry(equalTo("description"), equalTo("The created mailboxes introduce a cycle."))))
+ ));
+ }
+
+ @Test
+ public void setMailboxesShouldReturnNotCreatedWhenMailboxNameContainsPathDelimiter() throws Exception {
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"create\": {" +
+ " \"create-id01\" : {" +
+ " \"name\" : \"A.B.C.D\"" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .accept(ContentType.JSON)
+ .contentType(ContentType.JSON)
+ .header("Authorization", this.accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".notCreated", aMapWithSize(1))
+ .body(ARGUMENTS + ".notCreated", hasEntry(equalTo("create-id01"), Matchers.allOf(
+ hasEntry(equalTo("type"), equalTo("invalidArguments")),
+ hasEntry(equalTo("description"), equalTo("The mailbox 'A.B.C.D' contains an illegal character: '.'")))
+ ));
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNameException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNameException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNameException.java
new file mode 100644
index 0000000..1828eee
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNameException.java
@@ -0,0 +1,27 @@
+/****************************************************************
+ * 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.jmap.exceptions;
+
+public class MailboxNameException extends RuntimeException {
+
+ public MailboxNameException(String message) {
+ super(message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxParentNotFoundException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxParentNotFoundException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxParentNotFoundException.java
new file mode 100644
index 0000000..aadf5eb
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxParentNotFoundException.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.jmap.exceptions;
+
+public class MailboxParentNotFoundException extends RuntimeException {
+
+ private final String parentId;
+
+ public MailboxParentNotFoundException(String parentId) {
+ super(String.format("The parent mailbox '%s' was not found.", parentId));
+ this.parentId = parentId;
+ }
+
+ public String getParentId() {
+ return parentId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessor.java
index 73426f5..205528f 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessor.java
@@ -19,20 +19,134 @@
package org.apache.james.jmap.methods;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.jmap.exceptions.MailboxNameException;
+import org.apache.james.jmap.exceptions.MailboxParentNotFoundException;
+import org.apache.james.jmap.model.MailboxCreationId;
+import org.apache.james.jmap.model.SetError;
import org.apache.james.jmap.model.SetMailboxesRequest;
import org.apache.james.jmap.model.SetMailboxesResponse;
import org.apache.james.jmap.model.mailbox.Mailbox;
+import org.apache.james.jmap.model.mailbox.MailboxRequest;
+import org.apache.james.jmap.utils.SortingHierarchicalCollections;
+import org.apache.james.jmap.utils.DependencyGraph.CycleDetectedException;
+import org.apache.james.jmap.utils.MailboxUtils;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxExistsException;
+import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.mail.model.MailboxId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.fge.lambdas.Throwing;
+import com.google.common.annotations.VisibleForTesting;
public class SetMailboxesCreationProcessor<Id extends MailboxId> implements SetMailboxesProcessor<Id> {
- public SetMailboxesResponse process(SetMailboxesRequest request) {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class);
+
+ private final MailboxManager mailboxManager;
+ private final SortingHierarchicalCollections<Map.Entry<MailboxCreationId, MailboxRequest>, String> sortingHierarchicalCollections;
+ private final MailboxUtils<Id> mailboxUtils;
+
+ @Inject
+ @VisibleForTesting
+ SetMailboxesCreationProcessor(MailboxManager mailboxManager, MailboxUtils<Id> mailboxUtils) {
+ this.mailboxManager = mailboxManager;
+ this.sortingHierarchicalCollections =
+ new SortingHierarchicalCollections<>(
+ x -> x.getKey().getCreationId(),
+ x -> x.getValue().getParentId());
+ this.mailboxUtils = mailboxUtils;
+ }
+
+ public SetMailboxesResponse process(SetMailboxesRequest request, MailboxSession mailboxSession) {
SetMailboxesResponse.Builder builder = SetMailboxesResponse.builder();
- request.getCreate().entrySet().stream()
- .forEach(entry -> builder.creation(
- entry.getKey(),
- Mailbox.builder().name(entry.getValue().getName()).id("serverId").build()));
+ try {
+ Map<MailboxCreationId, String> creationIdsToCreatedMailboxId = new HashMap<>();
+ sortingHierarchicalCollections.sortFromRootToLeaf(request.getCreate().entrySet())
+ .forEach(entry ->
+ createMailbox(entry.getKey(), entry.getValue(), mailboxSession, creationIdsToCreatedMailboxId, builder));
+ } catch (CycleDetectedException e) {
+ markRequestsAsNotCreatedDueToCycle(request, builder);
+ }
return builder.build();
}
+ private void markRequestsAsNotCreatedDueToCycle(SetMailboxesRequest request, SetMailboxesResponse.Builder builder) {
+ request.getCreate().entrySet()
+ .forEach(entry ->
+ builder.notCreated(entry.getKey(),
+ SetError.builder()
+ .type("invalidArguments")
+ .description("The created mailboxes introduce a cycle.")
+ .build()));
+ }
+
+ private void createMailbox(MailboxCreationId mailboxCreationId, MailboxRequest mailboxRequest, MailboxSession mailboxSession,
+ Map<MailboxCreationId, String> creationIdsToCreatedMailboxId, SetMailboxesResponse.Builder builder) {
+ try {
+ ensureValidMailboxName(mailboxRequest, mailboxSession);
+ MailboxPath mailboxPath = getMailboxPath(mailboxRequest, creationIdsToCreatedMailboxId, mailboxSession);
+ mailboxManager.createMailbox(mailboxPath, mailboxSession);
+ Optional<Mailbox> mailbox = mailboxUtils.mailboxFromMailboxPath(mailboxPath, mailboxSession);
+ if (mailbox.isPresent()) {
+ builder.creation(mailboxCreationId, mailbox.get());
+ creationIdsToCreatedMailboxId.put(mailboxCreationId, mailbox.get().getId());
+ } else {
+ builder.notCreated(mailboxCreationId, SetError.builder()
+ .type("anErrorOccurred")
+ .description("An error occurred when creating the mailbox")
+ .build());
+ }
+ } catch (MailboxNameException | MailboxParentNotFoundException e) {
+ builder.notCreated(mailboxCreationId, SetError.builder()
+ .type("invalidArguments")
+ .description(e.getMessage())
+ .build());
+ } catch (MailboxExistsException e) {
+ String message = String.format("The mailbox '%s' already exists.", mailboxCreationId.getCreationId());
+ builder.notCreated(mailboxCreationId, SetError.builder()
+ .type("invalidArguments")
+ .description(message)
+ .build());
+ } catch (MailboxException e) {
+ String message = String.format("An error occurred when creating the mailbox '%s'", mailboxCreationId.getCreationId());
+ LOGGER.error(message, e);
+ builder.notCreated(mailboxCreationId, SetError.builder()
+ .type("anErrorOccurred")
+ .description(message)
+ .build());
+ }
+ }
+
+ private void ensureValidMailboxName(MailboxRequest mailboxRequest, MailboxSession mailboxSession) {
+ String name = mailboxRequest.getName();
+ char pathDelimiter = mailboxSession.getPathDelimiter();
+ if (name.contains(String.valueOf(pathDelimiter))) {
+ throw new MailboxNameException(String.format("The mailbox '%s' contains an illegal character: '%c'", name, pathDelimiter));
+ }
+ }
+
+ private MailboxPath getMailboxPath(MailboxRequest mailboxRequest, Map<MailboxCreationId, String> creationIdsToCreatedMailboxId, MailboxSession mailboxSession) throws MailboxException {
+ if (mailboxRequest.getParentId().isPresent()) {
+ String parentId = mailboxRequest.getParentId().get();
+ String parentName = mailboxUtils.getMailboxNameFromId(parentId, mailboxSession)
+ .orElseGet(Throwing.supplier(() ->
+ mailboxUtils.getMailboxNameFromId(creationIdsToCreatedMailboxId.get(MailboxCreationId.of(parentId)), mailboxSession)
+ .orElseThrow(() -> new MailboxParentNotFoundException(parentId))
+ ));
+
+ return new MailboxPath(mailboxSession.getPersonalSpace(), mailboxSession.getUser().getUserName(),
+ parentName + mailboxSession.getPathDelimiter() + mailboxRequest.getName());
+ }
+ return new MailboxPath(mailboxSession.getPersonalSpace(), mailboxSession.getUser().getUserName(), mailboxRequest.getName());
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesMethod.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesMethod.java
index 70b6e90..51ae92f 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesMethod.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesMethod.java
@@ -63,7 +63,7 @@ public class SetMailboxesMethod<Id extends MailboxId> implements Method {
Preconditions.checkArgument(request instanceof SetMailboxesRequest);
SetMailboxesRequest setMailboxesRequest = (SetMailboxesRequest) request;
return processors.stream()
- .map(processor -> processor.process(setMailboxesRequest))
+ .map(processor -> processor.process(setMailboxesRequest, mailboxSession))
.map(response -> toJmapResponse(clientId, response));
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesProcessor.java
index c9b7ef7..80f960e 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesProcessor.java
@@ -21,10 +21,11 @@ package org.apache.james.jmap.methods;
import org.apache.james.jmap.model.SetMailboxesRequest;
import org.apache.james.jmap.model.SetMailboxesResponse;
+import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.store.mail.model.MailboxId;
public interface SetMailboxesProcessor<Id extends MailboxId> {
- SetMailboxesResponse process(SetMailboxesRequest request);
+ SetMailboxesResponse process(SetMailboxesRequest request, MailboxSession mailboxSession);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java
index aa520b3..75aacd2 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
@@ -99,4 +100,20 @@ public class SetError {
public Optional<ImmutableSet<MessageProperty>> getProperties() {
return properties;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof SetError) {
+ SetError other = (SetError) obj;
+ return Objects.equal(this.type, other.type)
+ && Objects.equal(this.description, other.description)
+ && Objects.equal(this.properties, other.properties);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(type, description, properties);
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMailboxesResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMailboxesResponse.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMailboxesResponse.java
index 4322328..2d38706 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMailboxesResponse.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMailboxesResponse.java
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.jmap.model;
+import java.util.Map;
+
import org.apache.james.jmap.methods.Method;
import org.apache.james.jmap.model.mailbox.Mailbox;
@@ -31,10 +33,12 @@ public class SetMailboxesResponse implements Method.Response {
public static class Builder {
- private ImmutableMap.Builder<MailboxCreationId, Mailbox> created;
+ private final ImmutableMap.Builder<MailboxCreationId, Mailbox> created;
+ private final ImmutableMap.Builder<MailboxCreationId, SetError> notCreated;
private Builder() {
created = ImmutableMap.builder();
+ notCreated = ImmutableMap.builder();
}
public Builder creation(MailboxCreationId creationId, Mailbox mailbox) {
@@ -42,20 +46,35 @@ public class SetMailboxesResponse implements Method.Response {
return this;
}
+ public Builder notCreated(Map<MailboxCreationId, SetError> notCreated) {
+ this.notCreated.putAll(notCreated);
+ return this;
+ }
+
+ public Builder notCreated(MailboxCreationId mailboxCreationId, SetError setError) {
+ this.notCreated.put(mailboxCreationId, setError);
+ return this;
+ }
+
public SetMailboxesResponse build() {
- return new SetMailboxesResponse(created.build());
+ return new SetMailboxesResponse(created.build(), notCreated.build());
}
}
private final ImmutableMap<MailboxCreationId, Mailbox> created;
+ private final ImmutableMap<MailboxCreationId, SetError> notCreated;
- private SetMailboxesResponse(ImmutableMap<MailboxCreationId, Mailbox> created) {
+ private SetMailboxesResponse(ImmutableMap<MailboxCreationId, Mailbox> created, ImmutableMap<MailboxCreationId, SetError> notCreated) {
this.created = created;
+ this.notCreated = notCreated;
}
public ImmutableMap<MailboxCreationId, Mailbox> getCreated() {
return created;
}
+ public Map<MailboxCreationId, SetError> getNotCreated() {
+ return notCreated;
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/CollectionHierarchySorter.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/CollectionHierarchySorter.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/CollectionHierarchySorter.java
deleted file mode 100644
index 66fbf50..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/CollectionHierarchySorter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************
- * 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.jmap.utils;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import org.apache.james.jmap.utils.DependencyGraph.CycleDetectedException;
-
-import com.google.common.collect.Lists;
-
-public class CollectionHierarchySorter<T, Id> {
-
- private final Function<T, Id> index;
- private final Function<T, Optional<Id>> parentId;
-
- public CollectionHierarchySorter(Function<T, Id> index,
- Function<T, Optional<Id>> parentId) {
- this.index = index;
- this.parentId = parentId;
- }
-
- public List<T> sortFromRootToLeaf(Collection<T> elements) throws CycleDetectedException {
-
- Map<Id, T> mapOfElementsById = indexElementsById(elements);
-
- DependencyGraph<T> graph = new DependencyGraph<>(m ->
- parentId.apply(m).map(mapOfElementsById::get));
-
- elements.stream().forEach(graph::registerItem);
-
- return graph.getBuildChain().collect(Collectors.toList());
- }
-
- private Map<Id, T> indexElementsById(Collection<T> elements) {
- return elements.stream()
- .collect(Collectors.toMap(index, Function.identity()));
- }
-
- public List<T> sortFromLeafToRoot(Collection<T> elements) throws CycleDetectedException {
- return Lists.reverse(sortFromRootToLeaf(elements));
- }
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/SortingHierarchicalCollections.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/SortingHierarchicalCollections.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/SortingHierarchicalCollections.java
new file mode 100644
index 0000000..bbf0d2e
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/utils/SortingHierarchicalCollections.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.jmap.utils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.james.jmap.utils.DependencyGraph.CycleDetectedException;
+
+import com.google.common.collect.Lists;
+
+public class SortingHierarchicalCollections<T, Id> {
+
+ private final Function<T, Id> index;
+ private final Function<T, Optional<Id>> parentId;
+
+ public SortingHierarchicalCollections(Function<T, Id> index,
+ Function<T, Optional<Id>> parentId) {
+ this.index = index;
+ this.parentId = parentId;
+ }
+
+ public List<T> sortFromRootToLeaf(Collection<T> elements) throws CycleDetectedException {
+
+ Map<Id, T> mapOfElementsById = indexElementsById(elements);
+
+ DependencyGraph<T> graph = new DependencyGraph<>(m ->
+ parentId.apply(m).map(mapOfElementsById::get));
+
+ elements.stream().forEach(graph::registerItem);
+
+ return graph.getBuildChain().collect(Collectors.toList());
+ }
+
+ private Map<Id, T> indexElementsById(Collection<T> elements) {
+ return elements.stream()
+ .collect(Collectors.toMap(index, Function.identity()));
+ }
+
+ public List<T> sortFromLeafToRoot(Collection<T> elements) throws CycleDetectedException {
+ return Lists.reverse(sortFromRootToLeaf(elements));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessorTest.java
new file mode 100644
index 0000000..fe10145
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesCreationProcessorTest.java
@@ -0,0 +1,71 @@
+/****************************************************************
+ * 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.jmap.methods;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.jmap.model.MailboxCreationId;
+import org.apache.james.jmap.model.SetError;
+import org.apache.james.jmap.model.SetMailboxesRequest;
+import org.apache.james.jmap.model.SetMailboxesResponse;
+import org.apache.james.jmap.model.mailbox.MailboxRequest;
+import org.apache.james.jmap.utils.MailboxUtils;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.store.TestId;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SetMailboxesCreationProcessorTest {
+
+ private MailboxUtils<TestId> mailboxUtils;
+ private SetMailboxesCreationProcessor<TestId> sut;
+
+ @Before
+ @SuppressWarnings("unchecked")
+ public void setup() {
+ mailboxUtils = mock(MailboxUtils.class);
+ sut = new SetMailboxesCreationProcessor<>(mock(MailboxManager.class), mailboxUtils);
+ }
+
+ @Test
+ public void processShouldReturnNotCreatedWhenMailboxExceptionOccured() throws Exception {
+ String parentId = "parentId";
+ MailboxCreationId mailboxCreationId = MailboxCreationId.of("1");
+ SetMailboxesRequest request = SetMailboxesRequest.builder()
+ .create(mailboxCreationId, MailboxRequest.builder().name("name").parentId(parentId).build())
+ .build();
+
+ MailboxSession mailboxSession = mock(MailboxSession.class);
+ when(mailboxUtils.getMailboxNameFromId(parentId, mailboxSession))
+ .thenThrow(new MailboxException());
+
+ SetMailboxesResponse setMailboxesResponse = sut.process(request, mailboxSession);
+ assertThat(setMailboxesResponse.getCreated()).isEmpty();
+ assertThat(setMailboxesResponse.getNotCreated()).containsEntry(mailboxCreationId,
+ SetError.builder()
+ .type("anErrorOccurred")
+ .description("An error occurred when creating the mailbox '1'")
+ .build());
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesMethodTest.java
index af0d4a3..0019460 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMailboxesMethodTest.java
@@ -103,7 +103,7 @@ public class SetMailboxesMethodTest {
MailboxSession session = mock(MailboxSession.class);
@SuppressWarnings("unchecked")
SetMailboxesProcessor<TestId> creatorProcessor = mock(SetMailboxesProcessor.class);
- when(creatorProcessor.process(creationRequest)).thenReturn(creationResponse);
+ when(creatorProcessor.process(creationRequest, session)).thenReturn(creationResponse);
Stream<JmapResponse> actual =
new SetMailboxesMethod<>(ImmutableSet.of(creatorProcessor))
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/CollectionHierarchySorterTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/CollectionHierarchySorterTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/CollectionHierarchySorterTest.java
deleted file mode 100644
index 1870f9e..0000000
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/CollectionHierarchySorterTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************
- * 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.jmap.utils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.apache.james.jmap.model.mailbox.Mailbox;
-import org.apache.james.jmap.utils.DependencyGraph.CycleDetectedException;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class CollectionHierarchySorterTest {
-
- private CollectionHierarchySorter<Mailbox, String> sut;
-
- @Before
- public void setup() {
- sut = new CollectionHierarchySorter<>(Mailbox::getId, Mailbox::getParentId);
- }
-
- @Test
- public void sortFromRootToLeafShouldReturnOrderedMailbox() {
- // Given
- Mailbox inbox = Mailbox.builder().name("INBOX").id("INBOX").build();
- Mailbox a = Mailbox.builder().name("A").id("A").parentId("INBOX").build();
- Mailbox b = Mailbox.builder().name("B").id("B").parentId("INBOX").build();
- Mailbox c = Mailbox.builder().name("C").id("C").parentId("B").build();
- Mailbox d = Mailbox.builder().name("D").id("D").parentId("A").build();
- Mailbox e = Mailbox.builder().name("E").id("E").parentId("C").build();
- ImmutableList<Mailbox> input = ImmutableList.of(b, c, d, a, inbox, e);
-
- // When
- List<Mailbox> result = sut.sortFromRootToLeaf(input);
-
- // Then
- assertThat(result).extracting(Mailbox::getName).endsWith("C", "D", "E").startsWith("INBOX");
- }
-
- @Test
- public void sortFromRootToLeafEmptyMailboxShouldReturnEmpty() {
- ImmutableList<Mailbox> input = ImmutableList.of();
- List<Mailbox> result = sut.sortFromRootToLeaf(input);
- assertThat(result).isEmpty();
- }
-
- @Test
- public void sortFromRootToLeafOrphanMailboxesShouldReturnInput() {
- Mailbox a = Mailbox.builder().name("A").id("A").build();
- Mailbox b = Mailbox.builder().name("B").id("B").build();
- Mailbox c = Mailbox.builder().name("C").id("C").build();
-
- ImmutableList<Mailbox> input = ImmutableList.of(a, b, c);
- List<String> result = sut.sortFromRootToLeaf(input).stream()
- .map(Mailbox::getName)
- .collect(Collectors.toList());
-
- assertThat(result).containsExactly("A", "B", "C");
- }
-
- @Test(expected=CycleDetectedException.class)
- public void sortFromRootToLeafWithLoopShouldThrow() {
- Mailbox a = Mailbox.builder().name("A").id("A").parentId("B").build();
- Mailbox b = Mailbox.builder().name("B").id("B").parentId("A").build();
-
- ImmutableList<Mailbox> input = ImmutableList.of(a, b);
-
- sut.sortFromRootToLeaf(input);
- }
-
- @Test
- public void sortFromLeafToRootShouldReturnOrderedMailbox() {
- //Given
- Mailbox inbox = Mailbox.builder().name("INBOX").id("INBOX").build();
- Mailbox a = Mailbox.builder().name("A").id("A").parentId("INBOX").build();
- Mailbox b = Mailbox.builder().name("B").id("B").parentId("INBOX").build();
- Mailbox c = Mailbox.builder().name("C").id("C").parentId("B").build();
- Mailbox d = Mailbox.builder().name("D").id("D").parentId("A").build();
- Mailbox e = Mailbox.builder().name("E").id("E").parentId("C").build();
-
- ImmutableList<Mailbox> input = ImmutableList.of(b, c, d, a, inbox, e);
-
- //When
- List<Mailbox> result = sut.sortFromLeafToRoot(input);
-
- assertThat(result).extracting(Mailbox::getName).endsWith("INBOX").startsWith("E");
- }
-
- @Test
- public void sortFromLeafToRootEmptyMailboxShouldReturnEmpty() {
- ImmutableList<Mailbox> input = ImmutableList.of();
- List<Mailbox> result = sut.sortFromLeafToRoot(input);
- assertThat(result).isEmpty();
- }
-
- @Test
- public void sortFromLeafToRootOrphanMailboxesShouldReturnInput() {
- Mailbox a = Mailbox.builder().name("A").id("A").build();
- Mailbox b = Mailbox.builder().name("B").id("B").build();
- Mailbox c = Mailbox.builder().name("C").id("C").build();
-
- ImmutableList<Mailbox> input = ImmutableList.of(a, b, c);
- List<String> result = sut.sortFromLeafToRoot(input).stream()
- .map(Mailbox::getName)
- .collect(Collectors.toList());
-
- assertThat(result).containsExactly("C", "B", "A");
- }
-
- @Test(expected=CycleDetectedException.class)
- public void sortFromLeafToRootWithLoopShouldThrow() {
- Mailbox a = Mailbox.builder().name("A").id("A").parentId("B").build();
- Mailbox b = Mailbox.builder().name("B").id("B").parentId("A").build();
-
- ImmutableList<Mailbox> input = ImmutableList.of(a, b);
-
- sut.sortFromLeafToRoot(input);
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/68ab6176/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/SortingHierarchicalCollectionsTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/SortingHierarchicalCollectionsTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/SortingHierarchicalCollectionsTest.java
new file mode 100644
index 0000000..1437f88
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/utils/SortingHierarchicalCollectionsTest.java
@@ -0,0 +1,140 @@
+/****************************************************************
+ * 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.jmap.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.james.jmap.model.mailbox.Mailbox;
+import org.apache.james.jmap.utils.DependencyGraph.CycleDetectedException;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class SortingHierarchicalCollectionsTest {
+
+ private SortingHierarchicalCollections<Mailbox, String> sut;
+
+ @Before
+ public void setup() {
+ sut = new SortingHierarchicalCollections<>(Mailbox::getId, Mailbox::getParentId);
+ }
+
+ @Test
+ public void sortFromRootToLeafShouldReturnOrderedMailbox() {
+ // Given
+ Mailbox inbox = Mailbox.builder().name("INBOX").id("INBOX").build();
+ Mailbox a = Mailbox.builder().name("A").id("A").parentId("INBOX").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").parentId("INBOX").build();
+ Mailbox c = Mailbox.builder().name("C").id("C").parentId("B").build();
+ Mailbox d = Mailbox.builder().name("D").id("D").parentId("A").build();
+ Mailbox e = Mailbox.builder().name("E").id("E").parentId("C").build();
+ ImmutableList<Mailbox> input = ImmutableList.of(b, c, d, a, inbox, e);
+
+ // When
+ List<Mailbox> result = sut.sortFromRootToLeaf(input);
+
+ // Then
+ assertThat(result).extracting(Mailbox::getName).endsWith("C", "D", "E").startsWith("INBOX");
+ }
+
+ @Test
+ public void sortFromRootToLeafEmptyMailboxShouldReturnEmpty() {
+ ImmutableList<Mailbox> input = ImmutableList.of();
+ List<Mailbox> result = sut.sortFromRootToLeaf(input);
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void sortFromRootToLeafOrphanMailboxesShouldReturnInput() {
+ Mailbox a = Mailbox.builder().name("A").id("A").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").build();
+ Mailbox c = Mailbox.builder().name("C").id("C").build();
+
+ ImmutableList<Mailbox> input = ImmutableList.of(a, b, c);
+ List<String> result = sut.sortFromRootToLeaf(input).stream()
+ .map(Mailbox::getName)
+ .collect(Collectors.toList());
+
+ assertThat(result).containsExactly("A", "B", "C");
+ }
+
+ @Test(expected=CycleDetectedException.class)
+ public void sortFromRootToLeafWithLoopShouldThrow() {
+ Mailbox a = Mailbox.builder().name("A").id("A").parentId("B").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").parentId("A").build();
+
+ ImmutableList<Mailbox> input = ImmutableList.of(a, b);
+
+ sut.sortFromRootToLeaf(input);
+ }
+
+ @Test
+ public void sortFromLeafToRootShouldReturnOrderedMailbox() {
+ //Given
+ Mailbox inbox = Mailbox.builder().name("INBOX").id("INBOX").build();
+ Mailbox a = Mailbox.builder().name("A").id("A").parentId("INBOX").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").parentId("INBOX").build();
+ Mailbox c = Mailbox.builder().name("C").id("C").parentId("B").build();
+ Mailbox d = Mailbox.builder().name("D").id("D").parentId("A").build();
+ Mailbox e = Mailbox.builder().name("E").id("E").parentId("C").build();
+
+ ImmutableList<Mailbox> input = ImmutableList.of(b, c, d, a, inbox, e);
+
+ //When
+ List<Mailbox> result = sut.sortFromLeafToRoot(input);
+
+ assertThat(result).extracting(Mailbox::getName).endsWith("INBOX").startsWith("E");
+ }
+
+ @Test
+ public void sortFromLeafToRootEmptyMailboxShouldReturnEmpty() {
+ ImmutableList<Mailbox> input = ImmutableList.of();
+ List<Mailbox> result = sut.sortFromLeafToRoot(input);
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void sortFromLeafToRootOrphanMailboxesShouldReturnInput() {
+ Mailbox a = Mailbox.builder().name("A").id("A").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").build();
+ Mailbox c = Mailbox.builder().name("C").id("C").build();
+
+ ImmutableList<Mailbox> input = ImmutableList.of(a, b, c);
+ List<String> result = sut.sortFromLeafToRoot(input).stream()
+ .map(Mailbox::getName)
+ .collect(Collectors.toList());
+
+ assertThat(result).containsExactly("C", "B", "A");
+ }
+
+ @Test(expected=CycleDetectedException.class)
+ public void sortFromLeafToRootWithLoopShouldThrow() {
+ Mailbox a = Mailbox.builder().name("A").id("A").parentId("B").build();
+ Mailbox b = Mailbox.builder().name("B").id("B").parentId("A").build();
+
+ ImmutableList<Mailbox> input = ImmutableList.of(a, b);
+
+ sut.sortFromLeafToRoot(input);
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org