http://git-wip-us.apache.org/repos/asf/james-project/blob/ebcb09a0/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/Quotas.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/Quotas.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/Quotas.java
new file mode 100644
index 0000000..b088621
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/Quotas.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * 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.validation;
+
+import java.util.Optional;
+
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.eclipse.jetty.http.HttpStatus;
+
+public abstract class Quotas {
+
+    public static QuotaCount quotaCount(String serialized) {
+        return minusOneToEmpty(parseToLong(serialized))
+                .map(QuotaCount::count)
+                .orElse(QuotaCount.unlimited());
+    }
+
+    public static QuotaSize quotaSize(String serialized) {
+        return minusOneToEmpty(parseToLong(serialized))
+            .map(QuotaSize::size)
+            .orElse(QuotaSize.unlimited());
+    }
+
+    private static Optional<Long> minusOneToEmpty(long value) {
+        if (value < -1) {
+            throw generateInvalidInputError().haltError();
+        }
+        if (value == -1) {
+            return Optional.empty();
+        }
+        return Optional.of(value);
+    }
+
+    private static long parseToLong(String serialized) {
+        try {
+            return Long.valueOf(serialized);
+        } catch (IllegalArgumentException e) {
+            throw generateInvalidInputError()
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private static ErrorResponder generateInvalidInputError() {
+        return ErrorResponder.builder()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+            .message("Invalid quota. Need to be an integer value greater or 
equal to -1");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ebcb09a0/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
new file mode 100644
index 0000000..2293b50
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
@@ -0,0 +1,49 @@
+/****************************************************************
+ * 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 org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.webadmin.utils.JsonExtractException;
+import org.apache.james.webadmin.utils.JsonExtractor;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+public class QuotaValueDeserializerTest {
+
+    @Test
+    public void objectDeserializeShouldContainGivenValues() throws 
JsonExtractException {
+        String payload = "{\"count\":52,\"size\":42}";
+        QuotaDTO actual = new JsonExtractor<>(QuotaDTO.class,
+            new SimpleModule()
+                .addDeserializer(QuotaCount.class, new 
QuotaValueDeserializer<>(QuotaCount.unlimited(), QuotaCount::count))
+                .addDeserializer(QuotaSize.class, new 
QuotaValueDeserializer<>(QuotaSize.unlimited(), QuotaSize::size))
+        ).parse(payload);
+        Assertions.assertThat(actual)
+            .isEqualTo(
+                QuotaDTO
+                    .builder()
+                    .count(java.util.Optional.of(QuotaCount.count(52)))
+                    .size(java.util.Optional.of(QuotaSize.size(42)))
+                    .build());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/ebcb09a0/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
index cb8f745..68dd0fa 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
@@ -20,18 +20,23 @@
 package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
 import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.Map;
 
+import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
-import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
 import org.apache.james.metrics.logger.DefaultMetricFactory;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.jackson.QuotaModule;
 import org.apache.james.webadmin.service.GlobalQuotaService;
 import org.apache.james.webadmin.utils.JsonTransformer;
+import org.assertj.core.api.SoftAssertions;
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.After;
 import org.junit.Before;
@@ -51,7 +56,7 @@ public class GlobalQuotaRoutesTest {
         maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
         webAdminServer = WebAdminUtils.createWebAdminServer(
             new DefaultMetricFactory(),
-            new GlobalQuotaRoutes(new GlobalQuotaService(maxQuotaManager), new 
JsonTransformer()));
+            new GlobalQuotaRoutes(new GlobalQuotaService(maxQuotaManager), new 
JsonTransformer(new QuotaModule())));
         webAdminServer.configure(NO_CONFIGURATION);
         webAdminServer.await();
 
@@ -65,26 +70,20 @@ public class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void getCountQuotaCountShouldReturnUnlimitedByDefault() {
-        long quota =
-            given()
-                .get("/quota/count")
-            .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
-
-        assertThat(quota).isEqualTo(Quota.UNLIMITED);
+    public void getQuotaCountShouldReturnNoContentWhenUndefined() {
+        when()
+            .get("/quota/count")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
     }
 
     @Test
     public void getCountShouldReturnStoredValue() throws Exception {
         int value = 42;
-        maxQuotaManager.setDefaultMaxMessage(value);
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(value));
 
         Long actual =
-            given()
+            when()
                 .get("/quota/count")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -99,6 +98,7 @@ public class GlobalQuotaRoutesTest {
     public void putCountShouldRejectInvalid() {
         Map<String, Object> errors = given()
             .body("invalid")
+        .when()
             .put("/quota/count")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -108,17 +108,19 @@ public class GlobalQuotaRoutesTest {
             .jsonPath()
             .getMap(".");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0")
-            .containsEntry("cause", "For input string: \"invalid\"");
+        SoftAssertions.assertSoftly(softly ->
+            softly.assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1")
+                .containsEntry("cause", "For input string: \"invalid\""));
     }
 
     @Test
     public void putCountShouldRejectNegative() {
         Map<String, Object> errors = given()
-            .body("-1")
+            .body("-2")
+        .when()
             .put("/quota/count")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -128,57 +130,67 @@ public class GlobalQuotaRoutesTest {
             .jsonPath()
             .getMap(".");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0");
+        SoftAssertions.assertSoftly(softly ->
+            softly
+                .assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1"));
     }
 
     @Test
+    public void putCountShouldHandleMinusOneAsInfinite() throws 
MailboxException {
+        given()
+            .body("-1")
+        .when()
+            .put("/quota/count")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        
assertThat(maxQuotaManager.getDefaultMaxMessage()).contains(QuotaCount.unlimited());
+    }
+
+
+    @Test
     public void putCountShouldAcceptValidValue() throws Exception {
         given()
             .body("42")
+        .when()
             .put("/quota/count")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(42);
+        
assertThat(maxQuotaManager.getDefaultMaxMessage()).contains(QuotaCount.count(42));
     }
 
     @Test
     public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setDefaultMaxMessage(42);
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(42));
 
-        given()
+        when()
             .delete("/quota/count")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEmpty();
     }
 
     @Test
-    public void getSizeQuotaCountShouldReturnUnlimitedByDefault() {
-        long quota =
-            given()
-                .get("/quota/size")
-            .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
-
-        assertThat(quota).isEqualTo(Quota.UNLIMITED);
+    public void getQuotaSizeShouldReturnNothingByDefault() {
+        when()
+            .get("/quota/size")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
     }
 
     @Test
     public void getSizeShouldReturnStoredValue() throws Exception {
         long value = 42;
-        maxQuotaManager.setDefaultMaxStorage(value);
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(value));
 
 
         long quota =
-            given()
+            when()
                 .get("/quota/size")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -193,6 +205,7 @@ public class GlobalQuotaRoutesTest {
     public void putSizeShouldRejectInvalid() {
         Map<String, Object> errors = given()
             .body("invalid")
+        .when()
             .put("/quota/size")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -202,17 +215,32 @@ public class GlobalQuotaRoutesTest {
             .jsonPath()
             .getMap(".");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0")
-            .containsEntry("cause", "For input string: \"invalid\"");
+        SoftAssertions.assertSoftly(softly ->
+            softly
+                .assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1")
+                .containsEntry("cause", "For input string: \"invalid\""));
+    }
+
+    @Test
+    public void putSizeShouldHandleMinusOneAsInfinite() throws 
MailboxException {
+        given()
+            .body("-1")
+        .when()
+            .put("/quota/size")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        
assertThat(maxQuotaManager.getDefaultMaxStorage()).contains(QuotaSize.unlimited());
     }
 
     @Test
     public void putSizeShouldRejectNegative() {
         Map<String, Object> errors = given()
-            .body("-1")
+            .body("-2")
+        .when()
             .put("/quota/size")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -222,44 +250,47 @@ public class GlobalQuotaRoutesTest {
             .jsonPath()
             .getMap(".");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0");
+        SoftAssertions.assertSoftly(softly ->
+            softly
+                .assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1"));
     }
 
     @Test
     public void putSizeShouldAcceptValidValue() throws Exception {
         given()
             .body("42")
+        .when()
             .put("/quota/size")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
+        
assertThat(maxQuotaManager.getDefaultMaxStorage()).contains(QuotaSize.size(42));
     }
 
     @Test
     public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setDefaultMaxStorage(42);
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(42));
 
-        given()
+        when()
             .delete("/quota/count")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEmpty();
     }
 
     @Test
     public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
         int maxStorage = 42;
         int maxMessage = 52;
-        maxQuotaManager.setDefaultMaxStorage(maxStorage);
-        maxQuotaManager.setDefaultMaxMessage(maxMessage);
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(maxStorage));
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(maxMessage));
 
         JsonPath jsonPath =
-            given()
+            when()
                 .get("/quota")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -267,14 +298,16 @@ public class GlobalQuotaRoutesTest {
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong("size")).isEqualTo(maxStorage);
-        assertThat(jsonPath.getLong("count")).isEqualTo(maxMessage);
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(jsonPath.getLong("size")).isEqualTo(maxStorage);
+            softly.assertThat(jsonPath.getLong("count")).isEqualTo(maxMessage);
+        });
     }
 
     @Test
-    public void getQuotaShouldReturnBothDefaultValues() {
+    public void getQuotaShouldReturnNothingWhenNothingSet() {
         JsonPath jsonPath =
-            given()
+            when()
                 .get("/quota")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -282,17 +315,18 @@ public class GlobalQuotaRoutesTest {
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong("size")).isEqualTo(Quota.UNLIMITED);
-        assertThat(jsonPath.getLong("count")).isEqualTo(Quota.UNLIMITED);
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(jsonPath.getObject("size", Long.class)).isNull();
+            softly.assertThat(jsonPath.getObject("count", 
Long.class)).isNull();
+        });
     }
 
     @Test
-    public void getQuotaShouldReturnBothWhenNoCount() throws Exception {
-        int maxStorage = 42;
-        maxQuotaManager.setDefaultMaxStorage(maxStorage);
+    public void getQuotaShouldReturnOnlySizeWhenNoCount() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(42));
 
         JsonPath jsonPath =
-            given()
+            when()
                 .get("/quota")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -300,51 +334,111 @@ public class GlobalQuotaRoutesTest {
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong("size")).isEqualTo(maxStorage);
-        assertThat(jsonPath.getLong("count")).isEqualTo(Quota.UNLIMITED);
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(jsonPath.getLong("size")).isEqualTo(42);
+            softly.assertThat(jsonPath.getObject("count", 
Long.class)).isNull();
+        });
     }
 
     @Test
-    public void getQuotaShouldReturnBothWhenNoSize() throws Exception {
+    public void getQuotaShouldReturnOnlyCountWhenNoSize() throws Exception {
         int maxMessage = 42;
-        maxQuotaManager.setDefaultMaxMessage(maxMessage);
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(maxMessage));
 
 
         JsonPath jsonPath =
-            given()
+            when()
                 .get("/quota")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong("size")).isEqualTo(Quota.UNLIMITED);
-        assertThat(jsonPath.getLong("count")).isEqualTo(maxMessage);
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(jsonPath.getObject("size", Long.class)).isNull();
+            softly.assertThat(jsonPath.getLong("count")).isEqualTo(maxMessage);
+        });
     }
 
     @Test
     public void putQuotaShouldUpdateBothQuota() throws Exception {
         given()
             .body("{\"count\":52,\"size\":42}")
+        .when()
             .put("/quota")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(52);
-        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
+        SoftAssertions softly = new SoftAssertions();
+        
softly.assertThat(maxQuotaManager.getDefaultMaxMessage()).contains(QuotaCount.count(52));
+        
softly.assertThat(maxQuotaManager.getDefaultMaxStorage()).contains(QuotaSize.size(42));
     }
 
     @Test
-    public void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
+    public void putQuotaShouldSetBothQuotaToInfinite() throws Exception {
         given()
             .body("{\"count\":-1,\"size\":-1}")
+        .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        SoftAssertions softly = new SoftAssertions();
+        
softly.assertThat(maxQuotaManager.getDefaultMaxMessage()).contains(QuotaCount.unlimited());
+        
softly.assertThat(maxQuotaManager.getDefaultMaxStorage()).contains(QuotaSize.unlimited());
+    }
+
+    @Test
+    public void putQuotaShouldUnsetCountWhenNull() throws Exception {
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(42));
+        given()
+            .body("{\"count\":null,\"size\":43}")
+        .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEmpty();
+    }
+
+    @Test
+    public void putQuotaShouldUnsetSizeWhenNull() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(44));
+        given()
+            .body("{\"count\":45,\"size\":null}")
+        .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEmpty();
+    }
+
+    @Test
+    public void putQuotaShouldUnsetCountWhenAbsent() throws Exception {
+        maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(42));
+        given()
+            .body("{\"size\":43}")
+        .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEmpty();
+    }
+
+    @Test
+    public void putQuotaShouldUnsetSizeWhenAbsent() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(44));
+        given()
+            .body("{\"count\":45}")
+        .when()
             .put("/quota")
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
-        
assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(Quota.UNLIMITED);
+        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEmpty();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ebcb09a0/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index 86a09af..da4785c 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -21,7 +21,6 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
-import static org.apache.james.mailbox.model.Quota.UNLIMITED;
 import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -31,11 +30,14 @@ import org.apache.james.dnsservice.api.InMemoryDNSService;
 import org.apache.james.domainlist.memory.MemoryDomainList;
 import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
 import org.apache.james.mailbox.model.QuotaRoot;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
 import org.apache.james.metrics.api.NoopMetricFactory;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.memory.MemoryUsersRepository;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.jackson.QuotaModule;
 import org.apache.james.webadmin.service.UserQuotaService;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.eclipse.jetty.http.HttpStatus;
@@ -44,6 +46,7 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import com.google.common.collect.ImmutableSet;
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.path.json.JsonPath;
@@ -71,7 +74,8 @@ public class UserQuotaRoutesTest {
         usersRepository.setDomainList(memoryDomainList);
         usersRepository.addUser(BOB, PASSWORD);
         UserQuotaService userQuotaService = new 
UserQuotaService(maxQuotaManager);
-        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(usersRepository, 
userQuotaService, new JsonTransformer());
+        QuotaModule quotaModule = new QuotaModule();
+        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(usersRepository, 
userQuotaService, new JsonTransformer(quotaModule), 
ImmutableSet.of(quotaModule));
         webAdminServer = WebAdminUtils.createWebAdminServer(
             new NoopMetricFactory(),
             userQuotaRoutes);
@@ -97,23 +101,17 @@ public class UserQuotaRoutesTest {
     }
 
     @Test
-    public void getCountShouldReturnUnlimitedByDefault() throws 
UsersRepositoryException {
-        long quota =
-            given()
-                .get(QUOTA_USERS + "/" + BOB + "/" + COUNT)
-            .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
-
-        assertThat(quota).isEqualTo(UNLIMITED);
+    public void getCountShouldReturnNoContentByDefault() throws 
UsersRepositoryException {
+        given()
+            .get(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
     }
 
     @Test
     public void getCountShouldReturnStoredValue() throws Exception {
         int value = 42;
-        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), value);
+        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 
QuotaCount.count(value));
 
         Long actual =
             given()
@@ -154,14 +152,26 @@ public class UserQuotaRoutesTest {
         assertThat(errors)
             .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
             .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1")
             .containsEntry("cause", "For input string: \"invalid\"");
     }
 
     @Test
-    public void putCountShouldRejectNegative() throws Exception {
-        Map<String, Object> errors = given()
+    public void putCountShouldSetToInfiniteWhenMinusOne() throws Exception {
+        given()
             .body("-1")
+        .when()
+            .put(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).contains(QuotaCount.unlimited());
+    }
+
+    @Test
+    public void putCountShouldRejectNegativeOtherThanMinusOne() throws 
Exception {
+        Map<String, Object> errors = given()
+            .body("-2")
             .put(QUOTA_USERS + "/" + BOB + "/" + COUNT)
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -174,7 +184,7 @@ public class UserQuotaRoutesTest {
         assertThat(errors)
             .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
             .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0");
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
     }
 
     @Test
@@ -185,10 +195,9 @@ public class UserQuotaRoutesTest {
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).contains(QuotaCount.count(42));
     }
 
-
     @Test
     @Ignore("no link between quota and mailbox for now")
     public void putCountShouldRejectTooSmallValue() throws Exception {
@@ -211,15 +220,15 @@ public class UserQuotaRoutesTest {
 
 
     @Test
-    public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 42);
+    public void deleteCountShouldSetQuotaToEmpty() throws Exception {
+        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 
QuotaCount.count(42));
 
         given()
             .delete(QUOTA_USERS + "/" + BOB + "/" + COUNT)
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEmpty();
     }
 
     @Test
@@ -231,23 +240,17 @@ public class UserQuotaRoutesTest {
     }
 
     @Test
-    public void getSizeShouldReturnUnlimitedByDefault() throws 
UsersRepositoryException {
-        long quota =
-            given()
-                .get(QUOTA_USERS + "/" + BOB + "/" + SIZE)
-            .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
-
-        assertThat(quota).isEqualTo(UNLIMITED);
+    public void getSizeShouldReturnNoContentByDefault() throws 
UsersRepositoryException {
+        when()
+            .get(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
     }
 
     @Test
     public void getSizeShouldReturnStoredValue() throws Exception {
         long value = 42;
-        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), value);
+        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 
QuotaSize.size(value));
 
 
         long quota =
@@ -278,7 +281,7 @@ public class UserQuotaRoutesTest {
         assertThat(errors)
             .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
             .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1")
             .containsEntry("cause", "For input string: \"invalid\"");
     }
 
@@ -293,9 +296,21 @@ public class UserQuotaRoutesTest {
     }
 
     @Test
-    public void putSizeShouldRejectNegative() throws Exception {
-        Map<String, Object> errors = given()
+    public void putSizeShouldSetToInfiniteWhenMinusOne() throws Exception {
+        given()
             .body("-1")
+        .when()
+            .put(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).contains(QuotaSize.unlimited());
+    }
+
+    @Test
+    public void putSizeShouldRejectNegativeOtherThanMinusOne() throws 
Exception {
+        Map<String, Object> errors = given()
+            .body("-2")
             .put(QUOTA_USERS + "/" + BOB + "/" + SIZE)
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
@@ -308,18 +323,19 @@ public class UserQuotaRoutesTest {
         assertThat(errors)
             .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
             .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater than 0");
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
     }
 
     @Test
     public void putSizeShouldAcceptValidValue() throws Exception {
         given()
             .body("42")
+        .when()
             .put(QUOTA_USERS + "/" + BOB + "/" + SIZE)
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).contains(QuotaSize.size(42));
     }
 
     @Test
@@ -331,15 +347,15 @@ public class UserQuotaRoutesTest {
     }
 
     @Test
-    public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 42);
+    public void deleteSizeShouldSetQuotaToEmpty() throws Exception {
+        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 
QuotaSize.size(42));
 
         given()
             .delete(QUOTA_USERS + "/" + BOB + "/" + SIZE)
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEmpty();
     }
 
     @Test
@@ -354,8 +370,8 @@ public class UserQuotaRoutesTest {
     public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
         int maxStorage = 42;
         int maxMessage = 52;
-        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), maxStorage);
-        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), maxMessage);
+        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 
QuotaSize.size(maxStorage));
+        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 
QuotaCount.count(maxMessage));
 
         JsonPath jsonPath =
             given()
@@ -371,7 +387,7 @@ public class UserQuotaRoutesTest {
     }
 
     @Test
-    public void getQuotaShouldReturnBothDefaultValues() throws Exception {
+    public void getQuotaShouldReturnBothEmptyWhenDefaultValues() throws 
Exception {
         JsonPath jsonPath =
             given()
                 .get(QUOTA_USERS + "/" + BOB)
@@ -381,14 +397,14 @@ public class UserQuotaRoutesTest {
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong(SIZE)).isEqualTo(UNLIMITED);
-        assertThat(jsonPath.getLong(COUNT)).isEqualTo(UNLIMITED);
+        assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
+        assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
     }
 
     @Test
-    public void getQuotaShouldReturnBothWhenNoCount() throws Exception {
+    public void getQuotaShouldReturnSizeWhenNoCount() throws Exception {
         int maxStorage = 42;
-        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), maxStorage);
+        maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 
QuotaSize.size(maxStorage));
 
         JsonPath jsonPath =
             given()
@@ -400,13 +416,13 @@ public class UserQuotaRoutesTest {
                 .jsonPath();
 
         assertThat(jsonPath.getLong(SIZE)).isEqualTo(maxStorage);
-        assertThat(jsonPath.getLong(COUNT)).isEqualTo(UNLIMITED);
+        assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
     }
 
     @Test
     public void getQuotaShouldReturnBothWhenNoSize() throws Exception {
         int maxMessage = 42;
-        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), maxMessage);
+        maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 
QuotaCount.count(maxMessage));
 
 
         JsonPath jsonPath =
@@ -418,7 +434,7 @@ public class UserQuotaRoutesTest {
                 .extract()
                 .jsonPath();
 
-        assertThat(jsonPath.getLong(SIZE)).isEqualTo(UNLIMITED);
+        assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
         assertThat(jsonPath.getLong(COUNT)).isEqualTo(maxMessage);
     }
 
@@ -433,25 +449,25 @@ public class UserQuotaRoutesTest {
     @Test
     public void putQuotaShouldUpdateBothQuota() throws Exception {
         given()
-            .body("{\"" + COUNT + "\":52,\"" + SIZE + "\":42}")
+            .body("{\"count\":52,\"size\":42}")
             .put(QUOTA_USERS + "/" + BOB)
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(52);
-        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).contains(QuotaCount.count(52));
+        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).contains(QuotaSize.size(42));
     }
 
     @Test
     public void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
         given()
-            .body("{\"" + COUNT + "\":-1,\"" + SIZE + "\":-1}")
+            .body("{\"count\":null,\"count\":null}")
             .put(QUOTA_USERS + "/" + BOB)
         .then()
             .statusCode(HttpStatus.NO_CONTENT_204);
 
-        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
-        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+        
assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEmpty();
+        
assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEmpty();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/ebcb09a0/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/validation/QuotaValueTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/validation/QuotaValueTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/validation/QuotaValueTest.java
index 1cc2330..b57a754 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/validation/QuotaValueTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/validation/QuotaValueTest.java
@@ -22,6 +22,8 @@ package org.apache.james.webadmin.validation;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
 import org.junit.Test;
 
 import spark.HaltException;
@@ -30,50 +32,60 @@ public class QuotaValueTest {
 
     @Test
     public void quotaCountShouldThrowWhenNotANumber() {
-        assertThatThrownBy(() -> QuotaValue.quotaCount("invalid"))
+        assertThatThrownBy(() -> Quotas.quotaCount("invalid"))
             .isInstanceOf(HaltException.class);
     }
 
     @Test
     public void quotaCountShouldParseZero() {
-        assertThat(QuotaValue.quotaCount("0").asLong())
+        assertThat(Quotas.quotaCount("0").asLong())
             .isEqualTo(0);
     }
 
     @Test
     public void quotaCountShouldParsePositiveValue() {
-        assertThat(QuotaValue.quotaCount("42").asLong())
+        assertThat(Quotas.quotaCount("42").asLong())
             .isEqualTo(42);
     }
 
     @Test
+    public void quotaCountShouldBeUnlimitedOnMinusOne() {
+        assertThat(Quotas.quotaCount("-1")).isEqualTo(QuotaCount.unlimited());
+    }
+
+    @Test
     public void quotaCountShouldThrowOnNegativeNumber() {
-        assertThatThrownBy(() -> QuotaValue.quotaCount("-1"))
+        assertThatThrownBy(() -> Quotas.quotaCount("-2"))
             .isInstanceOf(HaltException.class);
     }
 
     @Test
     public void quotaSizeShouldThrowWhenNotANumber() {
-        assertThatThrownBy(() -> QuotaValue.quotaSize("invalid"))
+        assertThatThrownBy(() -> Quotas.quotaSize("invalid"))
             .isInstanceOf(HaltException.class);
     }
 
     @Test
     public void quotaSizeShouldParseZero() {
-        assertThat(QuotaValue.quotaSize("0").asLong())
+        assertThat(Quotas.quotaSize("0").asLong())
             .isEqualTo(0);
     }
 
     @Test
     public void quotaSizeShouldParsePositiveValue() {
-        assertThat(QuotaValue.quotaSize("42").asLong())
+        assertThat(Quotas.quotaSize("42").asLong())
             .isEqualTo(42);
     }
 
     @Test
+    public void quotaSizeShouldBeUnlimitedOnMinusOne() {
+        assertThat(Quotas.quotaSize("-1")).isEqualTo(QuotaSize.unlimited());
+
+    }
+
+    @Test
     public void quotaSizeShouldThrowOnNegativeNumber() {
-        assertThatThrownBy(() -> QuotaValue.quotaSize("-1"))
+        assertThatThrownBy(() -> Quotas.quotaSize("-2"))
             .isInstanceOf(HaltException.class);
     }
-
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to