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 bt...@apache.org on 2017/04/03 08:34:24 UTC

[1/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Repository: james-project
Updated Branches:
  refs/heads/master 6a8b56bf0 -> 5d3bedee1


http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
new file mode 100644
index 0000000..79a6915
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
@@ -0,0 +1,129 @@
+/****************************************************************
+ * 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.routes;
+
+import javax.inject.Inject;
+
+import org.apache.james.webadmin.Constants;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.service.UserMailboxesService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.james.webadmin.utils.MailboxHaveChildrenException;
+import org.apache.james.webadmin.validation.MailboxName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import spark.Service;
+
+public class UserMailboxesRoutes implements Routes {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesRoutes.class);
+
+    public static final String MAILBOX_NAME = ":mailboxName";
+    public static final String MAILBOXES = "mailboxes";
+    private static final String USER_NAME = ":userName";
+    public static final String USERS_BASE = "/users";
+    public static final String USER_MAILBOXES_BASE = USERS_BASE + Constants.SEPARATOR + USER_NAME + Constants.SEPARATOR + MAILBOXES;
+    public static final String SPECIFIC_MAILBOX = USER_MAILBOXES_BASE + Constants.SEPARATOR + MAILBOX_NAME;
+
+    private final UserMailboxesService userMailboxesService;
+    private final JsonTransformer jsonTransformer;
+
+    @Inject
+    public UserMailboxesRoutes(UserMailboxesService userMailboxesService, JsonTransformer jsonTransformer) {
+        this.userMailboxesService = userMailboxesService;
+        this.jsonTransformer = jsonTransformer;
+    }
+
+    @Override
+    public void define(Service service) {
+
+        service.put(SPECIFIC_MAILBOX, (request, response) -> {
+            try {
+                userMailboxesService.createMailbox(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)));
+                response.status(204);
+            } catch (IllegalStateException e) {
+                LOGGER.info("Invalid put on user mailbox", e);
+                response.status(404);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Attempt to create an invalid mailbox");
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.delete(SPECIFIC_MAILBOX, (request, response) -> {
+            try {
+                userMailboxesService.deleteMailbox(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)));
+                response.status(204);
+            } catch (IllegalStateException e) {
+                LOGGER.info("Invalid delete on user mailbox", e);
+                response.status(404);
+            } catch (MailboxHaveChildrenException e) {
+                LOGGER.info("Attempt to delete a mailbox with children");
+                response.status(409);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Attempt to create an invalid mailbox");
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.delete(USER_MAILBOXES_BASE, (request, response) -> {
+            try {
+                userMailboxesService.deleteMailboxes(request.params(USER_NAME));
+                response.status(204);
+            } catch (IllegalStateException e) {
+                LOGGER.info("Invalid delete on user mailboxes", e);
+                response.status(404);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.get(SPECIFIC_MAILBOX, (request, response) -> {
+            try {
+                if (userMailboxesService.testMailboxExists(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)))) {
+                    response.status(204);
+                } else {
+                    response.status(404);
+                }
+            } catch (IllegalStateException e) {
+                LOGGER.info("Invalid get on user mailbox", e);
+                response.status(404);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Attempt to create an invalid mailbox");
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.get(USER_MAILBOXES_BASE, (request, response) -> {
+            response.status(200);
+            try {
+                return userMailboxesService.listMailboxes(request.params(USER_NAME));
+            } catch (IllegalStateException e) {
+                LOGGER.info("Invalid get on user mailboxes", e);
+                response.status(404);
+                return Constants.EMPTY_BODY;
+            }
+        }, jsonTransformer);
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
new file mode 100644
index 0000000..469bdfb
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
@@ -0,0 +1,143 @@
+/****************************************************************
+ * 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.service;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+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.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.model.MailboxMetaData;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MailboxQuery;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.webadmin.dto.MailboxResponse;
+import org.apache.james.webadmin.utils.MailboxHaveChildrenException;
+import org.apache.james.webadmin.validation.MailboxName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+
+public class UserMailboxesService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesService.class);
+    private static final String USER_NAME = "webAdmin";
+
+    private final MailboxManager mailboxManager;
+    private final UsersRepository usersRepository;
+
+    @Inject
+    public UserMailboxesService(MailboxManager mailboxManager, UsersRepository usersRepository) {
+        this.mailboxManager = mailboxManager;
+        this.usersRepository = usersRepository;
+    }
+
+    public void createMailbox(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException {
+        usernamePreconditions(username);
+        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
+        try {
+            mailboxManager.createMailbox(
+                convertToMailboxPath(username, mailboxName.asString(), mailboxSession),
+                mailboxSession);
+        } catch (MailboxExistsException e) {
+            LOGGER.info("Attempt to create mailbox {} for user {} that already exists", mailboxName, username);
+        }
+    }
+
+    public void deleteMailboxes(String username) throws MailboxException, UsersRepositoryException {
+        usernamePreconditions(username);
+        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
+        listUserMailboxes(username, mailboxSession)
+            .map(MailboxMetaData::getPath)
+            .forEach(Throwing.consumer(mailboxPath -> deleteMailbox(mailboxSession, mailboxPath)));
+    }
+
+    public List<MailboxResponse> listMailboxes(String username) throws MailboxException, UsersRepositoryException {
+        usernamePreconditions(username);
+        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
+        return listUserMailboxes(username, mailboxSession)
+            .map(mailboxMetaData -> new MailboxResponse(mailboxMetaData.getPath().getName()))
+            .collect(Guavate.toImmutableList());
+    }
+
+    public boolean testMailboxExists(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException {
+        usernamePreconditions(username);
+        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
+        return mailboxManager.mailboxExists(
+            convertToMailboxPath(username, mailboxName.asString(), mailboxSession),
+            mailboxSession);
+    }
+
+    public void deleteMailbox(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException {
+        usernamePreconditions(username);
+        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
+        MailboxPath mailboxPath = convertToMailboxPath(username, mailboxName.asString(), mailboxSession);
+        listChildren(mailboxPath, mailboxSession)
+            .forEach(Throwing.consumer(path -> deleteMailbox(mailboxSession, path)));
+    }
+
+    private Stream<MailboxPath> listChildren(MailboxPath mailboxPath, MailboxSession mailboxSession) throws MailboxException {
+        return mailboxManager.search(createUserMailboxesQuery(mailboxPath.getUser()), mailboxSession)
+            .stream()
+            .map(MailboxMetaData::getPath)
+            .filter(path -> path.getHierarchyLevels(mailboxSession.getPathDelimiter()).contains(mailboxPath));
+    }
+
+    private void deleteMailbox(MailboxSession mailboxSession, MailboxPath mailboxPath) throws MailboxException {
+        try {
+            mailboxManager.deleteMailbox(mailboxPath, mailboxSession);
+        } catch (MailboxNotFoundException e) {
+            LOGGER.info("Attempt to delete mailbox {} for user {} that does not exists", mailboxPath.getName(), mailboxPath.getUser());
+        }
+    }
+
+    private void usernamePreconditions(String username) throws UsersRepositoryException {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(username));
+        Preconditions.checkState(usersRepository.contains(username));
+    }
+
+    private MailboxPath convertToMailboxPath(String username, String mailboxName, MailboxSession mailboxSession) {
+        return new MailboxPath(mailboxSession.getPersonalSpace(), username, mailboxName);
+    }
+
+    private Stream<MailboxMetaData> listUserMailboxes(String username, MailboxSession mailboxSession) throws MailboxException {
+        return mailboxManager.search(createUserMailboxesQuery(username), mailboxSession)
+            .stream();
+    }
+
+    private MailboxQuery createUserMailboxesQuery(String username) {
+        return MailboxQuery.builder()
+            .username(username)
+            .privateUserMailboxes()
+            .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java
new file mode 100644
index 0000000..ae8213e
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.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.webadmin.utils;
+
+public class MailboxHaveChildrenException extends Exception {
+
+    public MailboxHaveChildrenException(String mailboxName) {
+        super(mailboxName + "have children");
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/MailboxName.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
new file mode 100644
index 0000000..fdd079d
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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 com.google.common.base.CharMatcher;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+public class MailboxName {
+
+    public static final CharMatcher INVALID_CHARS_MATCHER = CharMatcher.anyOf("%*&#");
+    private final String mailboxName;
+
+    public MailboxName(String mailboxName) {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(mailboxName));
+        Preconditions.checkArgument(INVALID_CHARS_MATCHER.matchesNoneOf(mailboxName));
+        this.mailboxName = mailboxName;
+    }
+
+    public String asString() {
+        return mailboxName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
new file mode 100644
index 0000000..34df209
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class QuotaRequestTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void parseShouldThrowWhenNotANumber() {
+        expectedException.expect(NumberFormatException.class);
+
+        QuotaRequest.parse("invalid");
+    }
+
+    @Test
+    public void parseShouldThrowOnNegativeNumber() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        QuotaRequest.parse("-1");
+    }
+
+    @Test
+    public void parseShouldParseZero() {
+        assertThat(QuotaRequest.parse("0").getValue())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void parseShouldParsePositiveValue() {
+        assertThat(QuotaRequest.parse("42").getValue())
+            .isEqualTo(42);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/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
new file mode 100644
index 0000000..89f9fc0
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
@@ -0,0 +1,261 @@
+/****************************************************************
+ * 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.routes;
+
+import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
+import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Charsets;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+
+public class GlobalQuotaRoutesTest {
+
+    private WebAdminServer webAdminServer;
+    private InMemoryPerUserMaxQuotaManager maxQuotaManager;
+
+    @Before
+    public void setUp() throws Exception {
+        maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
+        webAdminServer = new WebAdminServer(
+            new DefaultMetricFactory(),
+            new GlobalQuotaRoutes(maxQuotaManager, new JsonTransformer()));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = new RequestSpecBuilder()
+            .setContentType(ContentType.JSON)
+            .setAccept(ContentType.JSON)
+            .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
+            .setPort(webAdminServer.getPort().toInt())
+            .build();
+    }
+
+    @After
+    public void stop() {
+        webAdminServer.destroy();
+    }
+
+    @Test
+    public void getCountQuotaCountShouldReturnUnlimitedByDefault() {
+        given()
+            .get(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is(String.valueOf(Quota.UNLIMITED)));
+    }
+
+    @Test
+    public void getCountShouldReturnStoredValue() throws Exception{
+        int value = 42;
+        maxQuotaManager.setDefaultMaxMessage(value);
+
+        given()
+            .get(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is(String.valueOf(value)));
+    }
+
+    @Test
+    public void putCountShouldRejectInvalid() throws Exception {
+        given()
+            .body("invalid")
+            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(400);
+    }
+
+    @Test
+    public void putCountShouldRejectNegative() throws Exception {
+        given()
+            .body("-1")
+            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(400);
+    }
+
+    @Test
+    public void putCountShouldAcceptValidValue() throws Exception {
+        given()
+            .body("42")
+            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(42);
+    }
+
+    @Test
+    public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
+        maxQuotaManager.setDefaultMaxMessage(42);
+
+        given()
+            .delete(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
+    }
+
+    @Test
+    public void getSizeQuotaCountShouldReturnUnlimitedByDefault() {
+        given()
+            .get(GlobalQuotaRoutes.SIZE_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is(String.valueOf(Quota.UNLIMITED)));
+    }
+
+    @Test
+    public void getSizeShouldReturnStoredValue() throws Exception{
+        int value = 42;
+        maxQuotaManager.setDefaultMaxStorage(value);
+
+        given()
+            .get(GlobalQuotaRoutes.SIZE_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is(String.valueOf(value)));
+    }
+
+    @Test
+    public void putSizeShouldRejectInvalid() throws Exception {
+        given()
+            .body("invalid")
+            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
+        .then()
+            .statusCode(400);
+    }
+
+    @Test
+    public void putSizeShouldRejectNegative() throws Exception {
+        given()
+            .body("-1")
+            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
+        .then()
+            .statusCode(400);
+    }
+
+    @Test
+    public void putSizeShouldAcceptValidValue() throws Exception {
+        given()
+            .body("42")
+            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
+    }
+
+    @Test
+    public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(42);
+
+        given()
+            .delete(GlobalQuotaRoutes.COUNT_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
+    }
+
+    @Test
+    public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(42);
+        maxQuotaManager.setDefaultMaxMessage(52);
+
+        given()
+            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is("{\"count\":52,\"size\":42}"));
+    }
+
+    @Test
+    public void getQuotaShouldReturnBothDefaultValues() throws Exception {
+        given()
+            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is("{\"count\":-1,\"size\":-1}"));
+    }
+
+    @Test
+    public void getQuotaShouldReturnBothWhenNoCount() throws Exception {
+        maxQuotaManager.setDefaultMaxStorage(42);
+
+        given()
+            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is("{\"count\":-1,\"size\":42}"));
+    }
+
+    @Test
+    public void getQuotaShouldReturnBothWhenNoSize() throws Exception {
+        maxQuotaManager.setDefaultMaxMessage(42);
+
+        given()
+            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(200)
+            .body(is("{\"count\":42,\"size\":-1}"));
+    }
+
+    @Test
+    public void putQuotaShouldUpdateBothQuota() throws Exception {
+        given()
+            .body("{\"count\":52,\"size\":42}")
+            .put(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(52);
+        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
+    }
+
+    @Test
+    public void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
+        given()
+            .body("{\"count\":-1,\"size\":-1}")
+            .put(GlobalQuotaRoutes.QUOTA_ENDPOINT)
+        .then()
+            .statusCode(204);
+
+        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
+        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(Quota.UNLIMITED);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
new file mode 100644
index 0000000..d19542f
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
@@ -0,0 +1,780 @@
+/****************************************************************
+ * 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.routes;
+
+import static com.jayway.restassured.RestAssured.when;
+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.apache.james.webadmin.Constants.SEPARATOR;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.apache.james.webadmin.routes.UserMailboxesRoutes.USERS_BASE;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
+import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxExistsException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MailboxQuery;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.store.FakeAuthorizator;
+import org.apache.james.mailbox.store.JVMMailboxPathLocker;
+import org.apache.james.mailbox.store.SimpleMailboxMetaData;
+import org.apache.james.mailbox.store.mail.model.DefaultMessageId;
+import org.apache.james.mailbox.store.mail.model.impl.MessageParser;
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.service.UserMailboxesService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+@RunWith(HierarchicalContextRunner.class)
+public class UserMailboxesRoutesTest {
+
+    public static final String USERNAME = "username";
+    public static final String MAILBOX_NAME = "myMailboxName";
+    private WebAdminServer webAdminServer;
+    private UsersRepository usersRepository;
+
+    private void createServer(MailboxManager mailboxManager) throws Exception {
+        usersRepository = mock(UsersRepository.class);
+        when(usersRepository.contains(USERNAME)).thenReturn(true);
+
+        webAdminServer = new WebAdminServer(
+            new DefaultMetricFactory(),
+            new UserMailboxesRoutes(new UserMailboxesService(mailboxManager, usersRepository), new JsonTransformer()));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = new RequestSpecBuilder()
+            .setContentType(ContentType.JSON)
+            .setAccept(ContentType.JSON)
+            .setBasePath(USERS_BASE + SEPARATOR + USERNAME + SEPARATOR + UserMailboxesRoutes.MAILBOXES)
+            .setPort(webAdminServer.getPort().toInt())
+            .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
+            .build();
+    }
+
+    @After
+    public void tearDown() {
+        webAdminServer.destroy();
+    }
+
+    public class NormalBehaviour {
+
+        @Before
+        public void setUp() throws Exception {
+            MessageId.Factory messageIdFactory = new DefaultMessageId.Factory();
+            InMemoryMailboxManager mailboxManager = new InMemoryMailboxManager(new InMemoryMailboxSessionMapperFactory(),
+                (userid, passwd) -> true,
+                FakeAuthorizator.defaultReject(),
+                new JVMMailboxPathLocker(),
+                new UnionMailboxACLResolver(),
+                new SimpleGroupMembershipResolver(),
+                new MessageParser(),
+                messageIdFactory);
+            mailboxManager.init();
+
+            createServer(mailboxManager);
+        }
+
+        @Test
+        public void getMailboxesShouldUserErrorFoundWithNonExistingUser() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get()
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void getShouldReturnNotFoundWithNonExistingUser() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnNotFoundWithNonExistingUser() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteShouldReturnNotFoundWithNonExistingUser() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void getShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get(MAILBOX_NAME + "*")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME+ "*")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME + "*")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void getShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get(MAILBOX_NAME + "%")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME+ "%")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME + "%")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void getShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get(MAILBOX_NAME + "#")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME+ "#")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME + "#")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void getShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .get(MAILBOX_NAME + "&")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME+ "&")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .put(MAILBOX_NAME + "&")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteMailboxesShouldReturnUserErrorWithNonExistingUser() throws Exception {
+            when(usersRepository.contains(USERNAME)).thenReturn(false);
+
+            when()
+                .delete()
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void getMailboxesShouldReturnEmptyListByDefault() {
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void putShouldReturnNotFoundWhenNoMailboxName() {
+            when()
+                .put()
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnNotFoundWhenJustSeparator() {
+            when()
+                .put(SEPARATOR)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnOk() {
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void putShouldReturnOkWhenIssuedTwoTimes() {
+            with()
+                .put(MAILBOX_NAME);
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void putShouldAddAMailbox() {
+            with()
+                .put(MAILBOX_NAME);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[{\"mailboxName\":\"myMailboxName\"}]"));
+        }
+
+        @Test
+        public void getShouldReturnNotFoundWhenMailboxDoesNotExist() {
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void getShouldReturnOkWhenMailboxExists() {
+            with()
+                .put(MAILBOX_NAME);
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenMailboxDoesNotExist() {
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenMailboxExists() {
+            with()
+                .put(MAILBOX_NAME);
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldRemoveMailbox() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .delete(MAILBOX_NAME);
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteMailboxesShouldReturnOkWhenNoMailboxes() {
+            when()
+                .delete()
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteMailboxesShouldReturnOkWhenMailboxes() {
+            with()
+                .put(MAILBOX_NAME);
+
+            when()
+                .delete()
+                .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteMailboxesShouldRemoveAllUserMailboxes() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put("otherMailbox");
+
+            with()
+                .delete();
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenMailboxHasChildren() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put(MAILBOX_NAME + ".child");
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldDeleteAMailboxAndItsChildren() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put(MAILBOX_NAME + ".child");
+
+            with()
+                .delete(MAILBOX_NAME);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void deleteShouldNotDeleteUnrelatedMailbox() {
+            String mailboxName = MAILBOX_NAME + "!child";
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put(mailboxName);
+
+            with()
+                .delete(MAILBOX_NAME);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[{\"mailboxName\":\"" + mailboxName + "\"}]"));
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenDeletingChildMailboxes() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put(MAILBOX_NAME + ".child");
+
+            when()
+                .delete(MAILBOX_NAME + ".child")
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldBeAbleToRemoveChildMailboxes() {
+            with()
+                .put(MAILBOX_NAME);
+
+            with()
+                .put(MAILBOX_NAME + ".child");
+
+            with()
+                .delete(MAILBOX_NAME + ".child");
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[{\"mailboxName\":\"myMailboxName\"}]"));
+        }
+    }
+
+    public class ExceptionHandling {
+
+        private MailboxManager mailboxManager;
+
+        @Before
+        public void setUp() throws Exception {
+            mailboxManager = mock(MailboxManager.class);
+            when(mailboxManager.createSystemSession(any(), any())).thenReturn(mock(MailboxSession.class));
+
+            createServer(mailboxManager);
+        }
+
+        @Test
+        public void putShouldGenerateInternalErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(mailboxManager).createMailbox(any(), any());
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void putShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
+            doThrow(new MailboxException()).when(mailboxManager).createMailbox(any(), any());
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void putShouldReturnOkOnMailboxExists() throws Exception {
+            doThrow(new MailboxExistsException(MAILBOX_NAME)).when(mailboxManager).createMailbox(any(), any());
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownExceptionOnDelete() throws Exception {
+            MailboxId mailboxId = InMemoryId.of(12);
+            when(mailboxManager.search(any(MailboxQuery.class), any()))
+                .thenReturn(
+                        ImmutableList.of(
+                                new SimpleMailboxMetaData(
+                                        new MailboxPath("#private", USERNAME, MAILBOX_NAME), mailboxId, '.')));
+            doThrow(new RuntimeException()).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownExceptionOnSearch() throws Exception {
+            when(mailboxManager.search(any(MailboxQuery.class), any())).thenThrow(new RuntimeException());
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownMailboxExceptionOnDelete() throws Exception {
+            MailboxId mailboxId = InMemoryId.of(12);
+            when(mailboxManager.search(any(MailboxQuery.class), any()))
+                .thenReturn(
+                        ImmutableList.of(
+                                new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, MAILBOX_NAME), mailboxId, '.')));
+            doThrow(new MailboxException()).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownMailboxExceptionOnSearch() throws Exception {
+            when(mailboxManager.search(any(MailboxQuery.class), any())).thenThrow(new MailboxException());
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldReturnOkOnMailboxDoesNotExists() throws Exception {
+            doThrow(new MailboxNotFoundException(MAILBOX_NAME)).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownExceptionWhenListingMailboxes() throws Exception {
+            doThrow(new RuntimeException()).when(mailboxManager).search(any(MailboxQuery.class), any());
+
+            when()
+                .delete()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnMailboxExceptionWhenListingMailboxes() throws Exception {
+            doThrow(new MailboxException()).when(mailboxManager).search(any(MailboxQuery.class), any());
+
+            when()
+                .delete()
+                .then()
+                .statusCode(500);
+        }
+
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnUnknownExceptionWhenRemovingMailboxes() throws Exception {
+            MailboxId mailboxId = InMemoryId.of(12);
+            when(mailboxManager.search(any(MailboxQuery.class), any()))
+                .thenReturn(
+                        ImmutableList.of(
+                                new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
+            doThrow(new RuntimeException()).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldReturnOkOnMailboxNotFoundExceptionWhenRemovingMailboxes() throws Exception {
+            MailboxId mailboxId = InMemoryId.of(12);
+            when(mailboxManager.search(any(MailboxQuery.class), any()))
+                .thenReturn(
+                        ImmutableList.of(new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
+            doThrow(new MailboxNotFoundException("any")).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete()
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldReturnInternalErrorOnMailboxExceptionWhenRemovingMailboxes() throws Exception {
+            MailboxId mailboxId = InMemoryId.of(12);
+            when(mailboxManager.search(any(MailboxQuery.class), any()))
+                .thenReturn(
+                        ImmutableList.of(new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
+            doThrow(new MailboxException()).when(mailboxManager).deleteMailbox(any(), any());
+
+            when()
+                .delete()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getShouldGenerateInternalErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(mailboxManager).mailboxExists(any(), any());
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
+            doThrow(new MailboxException()).when(mailboxManager).mailboxExists(any(), any());
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getMailboxesShouldGenerateInternalErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(mailboxManager).search(any(MailboxQuery.class), any());
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getMailboxesShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
+            doThrow(new MailboxException()).when(mailboxManager).search(any(MailboxQuery.class), any());
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getMailboxesShouldGenerateInternalErrorOnRepositoryException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getShouldGenerateInternalErrorOnRepositoryException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
+
+            when()
+                .get(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void putShouldGenerateInternalErrorOnRepositoryException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
+
+            when()
+                .put(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldGenerateInternalErrorOnRepositoryException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
+
+            when()
+                .delete(MAILBOX_NAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteMailboxesShouldGenerateInternalErrorOnRepositoryException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
+
+            when()
+                .delete()
+                .then()
+                .statusCode(500);
+        }
+
+    }
+
+}


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


[3/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/pom.xml b/server/protocols/webadmin/webadmin-core/pom.xml
new file mode 100644
index 0000000..151bbca
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/pom.xml
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>james-server</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta6-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>james-server-webadmin-core</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Apache James :: Server :: Web Admin :: Core</name>
+
+    <profiles>
+        <profile>
+            <id>noTest</id>
+            <activation>
+                <os>
+                    <family>windows</family>
+                </os>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-util-java8</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-lifecycle-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-jwt</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>metrics-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>metrics-logger</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.github.fge</groupId>
+                    <artifactId>throwing-lambdas</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.sparkjava</groupId>
+                    <artifactId>spark-core</artifactId>
+                    <version>2.5.5</version>
+                </dependency>
+                <dependency>
+                    <groupId>javax.inject</groupId>
+                    <artifactId>javax.inject</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.assertj</groupId>
+                    <artifactId>assertj-core</artifactId>
+                    <version>${assertj-3.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.mockito</groupId>
+                    <artifactId>mockito-core</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>nl.jqno.equalsverifier</groupId>
+                    <artifactId>equalsverifier</artifactId>
+                    <version>1.7.6</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <configuration>
+                            <archive>
+                                <manifest>
+                                    <mainClass>fully.qualified.MainClass</mainClass>
+                                </manifest>
+                            </archive>
+                            <descriptorRefs>
+                                <descriptorRef>jar-with-dependencies</descriptorRef>
+                            </descriptorRefs>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/CORSFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/CORSFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/CORSFilter.java
new file mode 100644
index 0000000..c4cfb29
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/CORSFilter.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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;
+
+import spark.Filter;
+import spark.Request;
+import spark.Response;
+
+
+public class CORSFilter implements Filter {
+    private final String urlCORSOrigin;
+
+    public CORSFilter(String urlCORSOrigin) {
+        this.urlCORSOrigin = urlCORSOrigin;
+    }
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+            response.header("Access-Control-Allow-Origin", urlCORSOrigin);
+            response.header("Access-Control-Request-Method", "DELETE, GET, POST, PUT");
+            response.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Constants.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Constants.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Constants.java
new file mode 100644
index 0000000..1031a86
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Constants.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.webadmin;
+
+public interface Constants {
+
+    String SEPARATOR = "/";
+    String EMPTY_BODY = "";
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/FixedPort.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/FixedPort.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/FixedPort.java
new file mode 100644
index 0000000..7ada8a1
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/FixedPort.java
@@ -0,0 +1,54 @@
+/****************************************************************
+ * 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;
+
+import java.util.Objects;
+
+import com.google.common.base.Preconditions;
+
+public class FixedPort implements Port {
+
+    private final int port;
+
+    public FixedPort(int port) {
+        Preconditions.checkArgument(port > 0 && port < 65536, "Port should be strictly contained between 0 and 65536");
+        this.port = port;
+    }
+
+    @Override
+    public int toInt() {
+        return port;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof FixedPort) {
+            FixedPort that = (FixedPort) o;
+
+            return Objects.equals(this.port, that.port);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(port);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Port.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Port.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Port.java
new file mode 100644
index 0000000..ff7a50b
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Port.java
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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;
+
+public interface Port {
+
+    int toInt();
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/RandomPort.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/RandomPort.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/RandomPort.java
new file mode 100644
index 0000000..2b3ab5d
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/RandomPort.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.base.Throwables;
+
+public class RandomPort implements Port {
+
+    public static int findFreePort() {
+        try (ServerSocket socket = new ServerSocket(0)) {
+            return socket.getLocalPort();
+        } catch (IOException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    private final Supplier<Integer> portSupplier;
+
+    public RandomPort() {
+        portSupplier = Suppliers.memoize(RandomPort::findFreePort);
+    }
+
+    @Override
+    public int toInt() {
+        return portSupplier.get();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Routes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Routes.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Routes.java
new file mode 100644
index 0000000..bc8554a
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/Routes.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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;
+
+import spark.Service;
+
+public interface Routes {
+
+    void define(Service service);
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/TlsConfiguration.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
new file mode 100644
index 0000000..d549ea3
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * 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;
+
+import java.util.Objects;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+public class TlsConfiguration {
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private String keystoreFilePath;
+        private String keystorePassword;
+        private String truststoreFilePath;
+        private String truststorePassword;
+
+        public Builder raw(String keystoreFilePath,
+                           String keystorePassword,
+                           String truststoreFilePath,
+                           String truststorePassword){
+            Preconditions.checkNotNull(keystoreFilePath);
+            Preconditions.checkNotNull(keystorePassword);
+
+            this.keystoreFilePath = keystoreFilePath;
+            this.keystorePassword = keystorePassword;
+            this.truststoreFilePath = truststoreFilePath;
+            this.truststorePassword = truststorePassword;
+            return this;
+        }
+
+        public Builder selfSigned(String keystoreFilePath, String keystorePassword){
+            Preconditions.checkNotNull(keystoreFilePath);
+            Preconditions.checkNotNull(keystorePassword);
+
+            this.keystoreFilePath = keystoreFilePath;
+            this.keystorePassword = keystorePassword;
+            return this;
+        }
+
+        public TlsConfiguration build() {
+            Preconditions.checkState(hasKeystoreInformation(), "If enabled, you need to provide keystore information");
+            Preconditions.checkState(optionalHasTrustStoreInformation(), "You need to provide both information about trustStore");
+            return new TlsConfiguration(keystoreFilePath, keystorePassword, truststoreFilePath, truststorePassword);
+        }
+
+        private boolean optionalHasTrustStoreInformation() {
+            return (truststoreFilePath == null) == (truststorePassword == null);
+        }
+
+        private boolean hasKeystoreInformation() {
+            return keystorePassword != null && keystoreFilePath != null;
+        }
+
+    }
+
+    private final String keystoreFilePath;
+    private final String keystorePassword;
+    private final String truststoreFilePath;
+    private final String truststorePassword;
+
+    @VisibleForTesting
+    TlsConfiguration(String keystoreFilePath, String keystorePassword, String truststoreFilePath, String truststorePassword) {
+        this.keystoreFilePath = keystoreFilePath;
+        this.keystorePassword = keystorePassword;
+        this.truststoreFilePath = truststoreFilePath;
+        this.truststorePassword = truststorePassword;
+    }
+
+    public String getKeystoreFilePath() {
+        return keystoreFilePath;
+    }
+
+    public String getKeystorePassword() {
+        return keystorePassword;
+    }
+
+    public String getTruststoreFilePath() {
+        return truststoreFilePath;
+    }
+
+    public String getTruststorePassword() {
+        return truststorePassword;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+       if (o instanceof TlsConfiguration) {
+           TlsConfiguration that = (TlsConfiguration) o;
+
+           return Objects.equals(this.keystoreFilePath, that.keystoreFilePath)
+               && Objects.equals(this.keystorePassword, that.keystorePassword)
+               && Objects.equals(this.truststoreFilePath, that.truststoreFilePath)
+               && Objects.equals(this.truststorePassword, that.truststorePassword);
+       }
+       return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(keystoreFilePath, keystorePassword, truststoreFilePath, truststorePassword);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
new file mode 100644
index 0000000..716645c
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
@@ -0,0 +1,169 @@
+/****************************************************************
+ * 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;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+public class WebAdminConfiguration {
+
+    public static final boolean DEFAULT_CORS_DISABLED = false;
+    public static final String CORS_ALL_ORIGINS = "*";
+
+    public static WebAdminConfiguration testingConfiguration() {
+        return WebAdminConfiguration.builder()
+            .enabled()
+            .port(new RandomPort())
+            .build();
+    }
+
+    public static final WebAdminConfiguration DISABLED_CONFIGURATION = WebAdminConfiguration.builder()
+        .disabled()
+        .build();
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private Optional<Boolean> enabled = Optional.empty();
+        private Optional<Port> port = Optional.empty();
+        private Optional<Boolean> enableCORS = Optional.empty();
+        private Optional<TlsConfiguration> tlsConfiguration = Optional.empty();
+        private Optional<String> urlCORSOrigin = Optional.empty();
+
+        public Builder tls(TlsConfiguration tlsConfiguration) {
+            this.tlsConfiguration = Optional.of(tlsConfiguration);
+            return this;
+        }
+
+        public Builder tls(Optional<TlsConfiguration> tlsConfiguration) {
+            this.tlsConfiguration = tlsConfiguration;
+            return this;
+        }
+
+        public Builder port(Port port) {
+            this.port = Optional.of(port);
+            return this;
+        }
+
+        public Builder enable(boolean isEnabled) {
+            this.enabled = Optional.of(isEnabled);
+            return this;
+        }
+        public Builder enabled() {
+            return enable(true);
+        }
+
+        public Builder disabled() {
+            return enable(false);
+        }
+
+        public Builder urlCORSOrigin(String origin) {
+            this.urlCORSOrigin = Optional.ofNullable(origin);
+            return this;
+        }
+
+        public Builder enableCORS(boolean isEnabled) {
+            this.enableCORS = Optional.of(isEnabled);
+            return this;
+        }
+
+        public Builder CORSenabled() {
+            return enableCORS(true);
+        }
+
+        public Builder CORSdisabled() {
+            return enableCORS(false);
+        }
+
+        public WebAdminConfiguration build() {
+            Preconditions.checkState(enabled.isPresent(), "You need to explicitly enable or disable WebAdmin server");
+            Preconditions.checkState(!enabled.get() || port.isPresent(), "You need to specify a port for WebAdminConfiguration");
+            return new WebAdminConfiguration(enabled.get(),
+                port,
+                tlsConfiguration,
+                enableCORS.orElse(DEFAULT_CORS_DISABLED),
+                urlCORSOrigin.orElse(CORS_ALL_ORIGINS));
+        }
+    }
+
+    private final boolean enabled;
+    private final Optional<Port> port;
+    private final Optional<TlsConfiguration> tlsConfiguration;
+    private final boolean enableCORS;
+    private final String urlCORSOrigin;
+
+    @VisibleForTesting
+    WebAdminConfiguration(boolean enabled, Optional<Port> port, Optional<TlsConfiguration> tlsConfiguration, boolean enableCORS, String urlCORSOrigin) {
+        this.enabled = enabled;
+        this.port = port;
+        this.tlsConfiguration = tlsConfiguration;
+        this.enableCORS = enableCORS;
+        this.urlCORSOrigin = urlCORSOrigin;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public String getUrlCORSOrigin() {
+        return urlCORSOrigin;
+    }
+
+    public Port getPort() {
+        return port.orElseThrow(() -> new IllegalStateException("No port was specified"));
+    }
+
+    public TlsConfiguration getTlsConfiguration() {
+        return tlsConfiguration.orElseThrow(() -> new IllegalStateException("No tls configuration"));
+    }
+
+    public boolean isEnableCORS() {
+        return enableCORS;
+    }
+
+    public boolean isTlsEnabled() {
+        return tlsConfiguration.isPresent();
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof WebAdminConfiguration) {
+            WebAdminConfiguration that = (WebAdminConfiguration) o;
+
+            return Objects.equals(this.enabled, that.enabled)
+                && Objects.equals(this.port, that.port)
+                && Objects.equals(this.tlsConfiguration, that.tlsConfiguration)
+                && Objects.equals(this.enableCORS, that.enableCORS)
+                && Objects.equals(this.urlCORSOrigin, that.urlCORSOrigin);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(enabled, port, tlsConfiguration, enableCORS, urlCORSOrigin);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminServer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminServer.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminServer.java
new file mode 100644
index 0000000..abce524
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminServer.java
@@ -0,0 +1,129 @@
+/****************************************************************
+ * 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;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.james.lifecycle.api.Configurable;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.webadmin.authentication.AuthenticationFilter;
+import org.apache.james.webadmin.authentication.NoAuthenticationFilter;
+import org.apache.james.webadmin.metric.MetricPostFilter;
+import org.apache.james.webadmin.metric.MetricPreFilter;
+import org.apache.james.webadmin.routes.CORSRoute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableSet;
+
+import spark.Service;
+
+public class WebAdminServer implements Configurable {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(WebAdminServer.class);
+    public static final HierarchicalConfiguration NO_CONFIGURATION = null;
+    public static final int DEFAULT_PORT = 8080;
+
+    private final WebAdminConfiguration configuration;
+    private final Set<Routes> routesList;
+    private final Service service;
+    private final AuthenticationFilter authenticationFilter;
+    private final MetricFactory metricFactory;
+
+    // Spark do not allow to retrieve allocated port when using a random port. Thus we generate the port.
+    @Inject
+    private WebAdminServer(WebAdminConfiguration configuration, Set<Routes> routesList, AuthenticationFilter authenticationFilter,
+                           MetricFactory metricFactory) {
+        this.configuration = configuration;
+        this.routesList = routesList;
+        this.authenticationFilter = authenticationFilter;
+        this.metricFactory = metricFactory;
+        this.service = Service.ignite();
+    }
+
+    @VisibleForTesting
+    public WebAdminServer(MetricFactory metricFactory, Routes... routes) throws IOException {
+        this(WebAdminConfiguration.testingConfiguration(),
+            ImmutableSet.copyOf(routes),
+            new NoAuthenticationFilter(),
+            metricFactory);
+    }
+
+    @Override
+    public void configure(HierarchicalConfiguration config) throws ConfigurationException {
+        if (configuration.isEnabled()) {
+            service.port(configuration.getPort().toInt());
+            configureHTTPS();
+            configureCORS();
+            configureMetrics();
+            service.before(authenticationFilter);
+            routesList.forEach(routes -> routes.define(service));
+            service.awaitInitialization();
+            LOGGER.info("Web admin server started");
+        }
+    }
+
+    private void configureMetrics() {
+        service.before(new MetricPreFilter(metricFactory));
+        service.after(new MetricPostFilter());
+    }
+
+    private void configureHTTPS() {
+        if (configuration.isTlsEnabled()) {
+            TlsConfiguration tlsConfiguration = configuration.getTlsConfiguration();
+            service.secure(tlsConfiguration.getKeystoreFilePath(),
+                tlsConfiguration.getKeystorePassword(),
+                tlsConfiguration.getTruststoreFilePath(),
+                tlsConfiguration.getTruststorePassword());
+            LOGGER.info("Web admin set up to use HTTPS");
+        }
+    }
+
+    private void configureCORS() {
+        if (configuration.isEnabled()) {
+            service.before(new CORSFilter(configuration.getUrlCORSOrigin()));
+            new CORSRoute().define(service);
+            LOGGER.info("Web admin set up to enable CORS from " + configuration.getUrlCORSOrigin());
+        }
+    }
+
+    @PreDestroy
+    public void destroy() {
+        if (configuration.isEnabled()) {
+            service.stop();
+            LOGGER.info("Web admin server stopped");
+        }
+    }
+
+    public void await() {
+        service.awaitInitialization();
+    }
+
+    public Port getPort() {
+        return configuration.getPort();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
new file mode 100644
index 0000000..f73b818
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
@@ -0,0 +1,25 @@
+/****************************************************************
+ * 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.authentication;
+
+import spark.Filter;
+
+public interface AuthenticationFilter extends Filter {
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
new file mode 100644
index 0000000..4832d6f
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * 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.authentication;
+
+import static spark.Spark.halt;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.jwt.JwtTokenVerifier;
+
+import spark.Request;
+import spark.Response;
+
+public class JwtFilter implements AuthenticationFilter {
+    public static final String AUTHORIZATION_HEADER_PREFIX = "Bearer ";
+    public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
+    public static final String OPTIONS = "OPTIONS";
+
+    private final JwtTokenVerifier jwtTokenVerifier;
+
+    @Inject
+    public JwtFilter(JwtTokenVerifier jwtTokenVerifier) {
+        this.jwtTokenVerifier = jwtTokenVerifier;
+    }
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+        if (request.requestMethod() != OPTIONS) {
+            Optional<String> bearer = Optional.ofNullable(request.headers(AUTHORIZATION_HEADER_NAME))
+                .filter(value -> value.startsWith(AUTHORIZATION_HEADER_PREFIX))
+                .map(value -> value.substring(AUTHORIZATION_HEADER_PREFIX.length()));
+
+            checkHeaderPresent(bearer);
+            checkValidSignature(bearer);
+            checkIsAdmin(bearer);
+        }
+    }
+
+    private void checkHeaderPresent(Optional<String> bearer) {
+        if (!bearer.isPresent()) {
+            halt(401, "No Bearer header.");
+        }
+    }
+
+    private void checkValidSignature(Optional<String> bearer) {
+        if (!jwtTokenVerifier.verify(bearer.get())) {
+            halt(401, "Invalid Bearer header.");
+        }
+    }
+
+    private void checkIsAdmin(Optional<String> bearer) {
+        if (!jwtTokenVerifier.hasAttribute("admin", true, bearer.get())) {
+            halt(401, "Non authorized user.");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
new file mode 100644
index 0000000..45a2f5b
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
@@ -0,0 +1,31 @@
+/****************************************************************
+ * 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.authentication;
+
+import spark.Request;
+import spark.Response;
+
+public class NoAuthenticationFilter implements AuthenticationFilter {
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
new file mode 100644
index 0000000..4d9b8b7
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.metric;
+
+import org.apache.james.metrics.api.TimeMetric;
+
+import spark.Filter;
+import spark.Request;
+import spark.Response;
+
+public class MetricPostFilter implements Filter {
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+        if (request.attribute(MetricPreFilter.METRICS) instanceof TimeMetric) {
+            TimeMetric timeMetric = request.attribute(MetricPreFilter.METRICS);
+            timeMetric.stopAndPublish();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
new file mode 100644
index 0000000..1ed9d76
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * 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.metric;
+
+import org.apache.james.metrics.api.MetricFactory;
+
+import spark.Filter;
+import spark.Request;
+import spark.Response;
+
+public class MetricPreFilter implements Filter {
+    public static final String METRICS = "metrics";
+    private final MetricFactory metricFactory;
+
+    public MetricPreFilter(MetricFactory metricFactory) {
+        this.metricFactory = metricFactory;
+    }
+
+    @Override
+    public void handle(Request request, Response response) throws Exception {
+        request.attribute(METRICS, metricFactory.timer("webAdmin"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
new file mode 100644
index 0000000..39e9bd7
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
@@ -0,0 +1,42 @@
+/****************************************************************
+ * 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.routes;
+
+import org.apache.james.webadmin.Routes;
+
+import spark.Service;
+
+public class CORSRoute implements Routes {
+
+    @Override
+    public void define(Service service) {
+        service.options("/*", (request, response) -> {
+            String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
+            if (accessControlRequestHeaders != null) {
+                response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
+            }
+            String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
+            if (accessControlRequestMethod != null) {
+                response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
+            }
+            return "";
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java
new file mode 100644
index 0000000..dc6b578
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.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.webadmin.utils;
+
+public class JsonExtractException extends Exception {
+
+    public JsonExtractException(Throwable throwable) {
+        super(throwable);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
new file mode 100644
index 0000000..f4eb420
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
@@ -0,0 +1,44 @@
+/****************************************************************
+ * 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.utils;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JsonExtractor<Request> {
+
+    private final ObjectMapper objectMapper;
+    private final Class<Request> type;
+
+    public JsonExtractor(Class<Request> type) {
+        this.objectMapper = new ObjectMapper();
+        this.type = type;
+    }
+
+    public Request parse(String text) throws JsonExtractException {
+        try {
+            return objectMapper.readValue(text, type);
+        } catch (IOException e) {
+            throw new JsonExtractException(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
new file mode 100644
index 0000000..3c32f0c
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * 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.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+import spark.ResponseTransformer;
+
+public class JsonTransformer implements ResponseTransformer {
+
+    private final ObjectMapper objectMapper;
+
+    public JsonTransformer() {
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+    }
+
+    @Override
+    public String render(Object o) throws JsonProcessingException {
+        return objectMapper.writeValueAsString(o);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/FixedPortTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/FixedPortTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/FixedPortTest.java
new file mode 100644
index 0000000..2712daa
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/FixedPortTest.java
@@ -0,0 +1,57 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class FixedPortTest {
+
+    @Test
+    public void toIntShouldThrowOnNegativePort() {
+        assertThatThrownBy(() -> new FixedPort(-1)).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void toIntShouldThrowOnNullPort() {
+        assertThatThrownBy(() -> new FixedPort(0)).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void toIntShouldThrowOnTooBigNumbers() {
+        assertThatThrownBy(() -> new FixedPort(65536)).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void toIntShouldReturnedDesiredPort() {
+        int expectedPort = 452;
+        assertThat(new FixedPort(expectedPort).toInt()).isEqualTo(expectedPort);
+    }
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(FixedPort.class).verify();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/RandomPortTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/RandomPortTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/RandomPortTest.java
new file mode 100644
index 0000000..07d1996
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/RandomPortTest.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.webadmin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class RandomPortTest {
+
+    @Test
+    public void toIntShouldReturnTwoTimeTheSameResult() {
+        RandomPort testee = new RandomPort();
+        assertThat(testee.toInt()).isEqualTo(testee.toInt());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
new file mode 100644
index 0000000..2d93282
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
@@ -0,0 +1,88 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class TlsConfigurationTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void buildShouldThrowWhenNotEnabled() {
+        expectedException.expect(IllegalStateException.class);
+
+        TlsConfiguration.builder().build();
+    }
+
+    @Test
+    public void buildShouldThrowWhenEnableWithoutKeystore() {
+        expectedException.expect(IllegalStateException.class);
+
+        TlsConfiguration.builder().build();
+    }
+
+    @Test
+    public void selfSignedShouldThrowOnNullKeyStorePath() {
+        expectedException.expect(NullPointerException.class);
+
+        TlsConfiguration.builder()
+            .selfSigned(null, "abc");
+    }
+
+    @Test
+    public void selfSignedShouldThrowOnNullKeyStorePassword() {
+        expectedException.expect(NullPointerException.class);
+
+        TlsConfiguration.builder()
+            .selfSigned("abc", null);
+    }
+
+    @Test
+    public void buildShouldWorkOnSelfSignedHttps() {
+        assertThat(
+            TlsConfiguration.builder()
+                .selfSigned("abcd", "efgh")
+                .build())
+            .isEqualTo(new TlsConfiguration("abcd", "efgh", null, null));
+    }
+
+    @Test
+    public void buildShouldWorkOnTrustedHttps() {
+        assertThat(
+            TlsConfiguration.builder()
+                .raw("a", "b", "c", "d")
+                .build())
+            .isEqualTo(new TlsConfiguration("a", "b", "c", "d"));
+    }
+
+    @Test
+    public void shouldRespectBeanContract() {
+        EqualsVerifier.forClass(TlsConfiguration.class).verify();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
new file mode 100644
index 0000000..1030dcf
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
@@ -0,0 +1,181 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class WebAdminConfigurationTest {
+
+    public static final FixedPort PORT = new FixedPort(80);
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void buildShouldThrowWhenNoPortButEnabled() {
+        expectedException.expect(IllegalStateException.class);
+
+        WebAdminConfiguration.builder().enabled().build();
+    }
+
+    @Test
+    public void buildShouldWorkWithoutPortWhenDisabled() {
+        assertThat(WebAdminConfiguration.builder()
+            .disabled()
+            .build())
+            .extracting(WebAdminConfiguration::isEnabled)
+            .containsExactly(false);
+    }
+
+    @Test
+    public void buildShouldFailOnNoEnable() {
+        expectedException.expect(IllegalStateException.class);
+
+        WebAdminConfiguration.builder().port(PORT).build();
+    }
+
+    @Test
+    public void builderShouldBuildWithRightPort() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .build())
+            .extracting(WebAdminConfiguration::getPort)
+            .containsExactly(PORT);
+    }
+
+
+    @Test
+    public void builderShouldBuildWithEnable() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .build())
+            .extracting(WebAdminConfiguration::isEnabled)
+            .containsExactly(true);
+    }
+
+    @Test
+    public void builderShouldAcceptHttps() {
+        TlsConfiguration tlsConfiguration = TlsConfiguration.builder()
+            .selfSigned("abcd", "efgh")
+            .build();
+
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .tls(tlsConfiguration)
+                .port(PORT)
+                .build())
+            .extracting(WebAdminConfiguration::getTlsConfiguration)
+            .containsExactly(tlsConfiguration);
+    }
+
+    @Test
+    public void builderShouldReturnTlsEnableWhenTlsConfiguration() {
+        TlsConfiguration tlsConfiguration = TlsConfiguration.builder()
+            .selfSigned("abcd", "efgh")
+            .build();
+
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .tls(tlsConfiguration)
+                .port(PORT)
+                .build())
+            .extracting(WebAdminConfiguration::getTlsConfiguration)
+            .containsExactly(tlsConfiguration);
+    }
+
+    @Test
+    public void builderShouldReturnTlsDisableWhenNoTlsConfiguration() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .build())
+            .extracting(WebAdminConfiguration::isTlsEnabled)
+            .containsExactly(false);
+    }
+
+    @Test
+    public void builderShouldCORSEnabled() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .CORSenabled()
+                .build())
+            .extracting(WebAdminConfiguration::isEnableCORS)
+            .containsExactly(true);
+    }
+
+    @Test
+    public void builderShouldAcceptAllOriginsByDefault() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .CORSenabled()
+                .build())
+            .extracting(WebAdminConfiguration::getUrlCORSOrigin)
+            .containsExactly("*");
+    }
+
+    @Test
+    public void builderShouldCORSDisabled() {
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .CORSdisabled()
+                .build())
+            .extracting(WebAdminConfiguration::isEnableCORS)
+            .containsExactly(false);
+    }
+
+    @Test
+    public void builderShouldCORSWithOrigin() {
+        String origin = "linagora.com";
+        assertThat(
+            WebAdminConfiguration.builder()
+                .enabled()
+                .port(PORT)
+                .CORSenabled()
+                .urlCORSOrigin(origin)
+                .build())
+            .extracting(WebAdminConfiguration::getUrlCORSOrigin)
+            .containsExactly(origin);
+    }
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(WebAdminConfiguration.class).verify();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
new file mode 100644
index 0000000..6512ddb
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * 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.authentication;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.jwt.JwtTokenVerifier;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.collect.ImmutableSet;
+
+import spark.HaltException;
+import spark.Request;
+import spark.Response;
+
+public class JwtFilterTest {
+
+    public static final Matcher<HaltException> STATUS_CODE_MATCHER_401 = new BaseMatcher<HaltException>() {
+        @Override
+        public boolean matches(Object o) {
+            if (o instanceof HaltException) {
+                HaltException haltException = (HaltException) o;
+                return haltException.statusCode() == 401;
+            }
+            return false;
+        }
+
+        @Override
+        public void describeTo(Description description) {}
+    };
+
+    private JwtTokenVerifier jwtTokenVerifier;
+    private JwtFilter jwtFilter;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        jwtTokenVerifier = mock(JwtTokenVerifier.class);
+        jwtFilter = new JwtFilter(jwtTokenVerifier);
+    }
+
+    @Test
+    public void handleShouldRejectRequestWithHeaders() throws Exception {
+        Request request = mock(Request.class);
+        when(request.headers()).thenReturn(ImmutableSet.of());
+
+        expectedException.expect(HaltException.class);
+        expectedException.expect(STATUS_CODE_MATCHER_401);
+
+        jwtFilter.handle(request, mock(Response.class));
+    }
+
+    @Test
+    public void handleShouldRejectRequestWithBearersHeaders() throws Exception {
+        Request request = mock(Request.class);
+        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Invalid value");
+
+        expectedException.expect(HaltException.class);
+        expectedException.expect(STATUS_CODE_MATCHER_401);
+
+        jwtFilter.handle(request, mock(Response.class));
+    }
+
+    @Test
+    public void handleShouldRejectRequestWithInvalidBearerHeaders() throws Exception {
+        Request request = mock(Request.class);
+        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
+        when(jwtTokenVerifier.verify("value")).thenReturn(false);
+
+        expectedException.expect(HaltException.class);
+        expectedException.expect(STATUS_CODE_MATCHER_401);
+
+        jwtFilter.handle(request, mock(Response.class));
+    }
+
+    @Test
+    public void handleShouldRejectRequestWithoutAdminClaim() throws Exception {
+        Request request = mock(Request.class);
+        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
+        when(jwtTokenVerifier.verify("value")).thenReturn(true);
+        when(jwtTokenVerifier.hasAttribute("admin", true, "value")).thenReturn(false);
+
+        expectedException.expect(HaltException.class);
+        expectedException.expect(STATUS_CODE_MATCHER_401);
+
+        jwtFilter.handle(request, mock(Response.class));
+    }
+
+    @Test
+    public void handleShouldAcceptValidJwt() throws Exception {
+        Request request = mock(Request.class);
+        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
+        when(jwtTokenVerifier.verify("value")).thenReturn(true);
+        when(jwtTokenVerifier.hasAttribute("admin", true, "value")).thenReturn(true);
+
+        jwtFilter.handle(request, mock(Response.class));
+    }
+}


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


[5/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
deleted file mode 100644
index 716645c..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java
+++ /dev/null
@@ -1,169 +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.webadmin;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-
-public class WebAdminConfiguration {
-
-    public static final boolean DEFAULT_CORS_DISABLED = false;
-    public static final String CORS_ALL_ORIGINS = "*";
-
-    public static WebAdminConfiguration testingConfiguration() {
-        return WebAdminConfiguration.builder()
-            .enabled()
-            .port(new RandomPort())
-            .build();
-    }
-
-    public static final WebAdminConfiguration DISABLED_CONFIGURATION = WebAdminConfiguration.builder()
-        .disabled()
-        .build();
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-        private Optional<Boolean> enabled = Optional.empty();
-        private Optional<Port> port = Optional.empty();
-        private Optional<Boolean> enableCORS = Optional.empty();
-        private Optional<TlsConfiguration> tlsConfiguration = Optional.empty();
-        private Optional<String> urlCORSOrigin = Optional.empty();
-
-        public Builder tls(TlsConfiguration tlsConfiguration) {
-            this.tlsConfiguration = Optional.of(tlsConfiguration);
-            return this;
-        }
-
-        public Builder tls(Optional<TlsConfiguration> tlsConfiguration) {
-            this.tlsConfiguration = tlsConfiguration;
-            return this;
-        }
-
-        public Builder port(Port port) {
-            this.port = Optional.of(port);
-            return this;
-        }
-
-        public Builder enable(boolean isEnabled) {
-            this.enabled = Optional.of(isEnabled);
-            return this;
-        }
-        public Builder enabled() {
-            return enable(true);
-        }
-
-        public Builder disabled() {
-            return enable(false);
-        }
-
-        public Builder urlCORSOrigin(String origin) {
-            this.urlCORSOrigin = Optional.ofNullable(origin);
-            return this;
-        }
-
-        public Builder enableCORS(boolean isEnabled) {
-            this.enableCORS = Optional.of(isEnabled);
-            return this;
-        }
-
-        public Builder CORSenabled() {
-            return enableCORS(true);
-        }
-
-        public Builder CORSdisabled() {
-            return enableCORS(false);
-        }
-
-        public WebAdminConfiguration build() {
-            Preconditions.checkState(enabled.isPresent(), "You need to explicitly enable or disable WebAdmin server");
-            Preconditions.checkState(!enabled.get() || port.isPresent(), "You need to specify a port for WebAdminConfiguration");
-            return new WebAdminConfiguration(enabled.get(),
-                port,
-                tlsConfiguration,
-                enableCORS.orElse(DEFAULT_CORS_DISABLED),
-                urlCORSOrigin.orElse(CORS_ALL_ORIGINS));
-        }
-    }
-
-    private final boolean enabled;
-    private final Optional<Port> port;
-    private final Optional<TlsConfiguration> tlsConfiguration;
-    private final boolean enableCORS;
-    private final String urlCORSOrigin;
-
-    @VisibleForTesting
-    WebAdminConfiguration(boolean enabled, Optional<Port> port, Optional<TlsConfiguration> tlsConfiguration, boolean enableCORS, String urlCORSOrigin) {
-        this.enabled = enabled;
-        this.port = port;
-        this.tlsConfiguration = tlsConfiguration;
-        this.enableCORS = enableCORS;
-        this.urlCORSOrigin = urlCORSOrigin;
-    }
-
-    public boolean isEnabled() {
-        return enabled;
-    }
-
-    public String getUrlCORSOrigin() {
-        return urlCORSOrigin;
-    }
-
-    public Port getPort() {
-        return port.orElseThrow(() -> new IllegalStateException("No port was specified"));
-    }
-
-    public TlsConfiguration getTlsConfiguration() {
-        return tlsConfiguration.orElseThrow(() -> new IllegalStateException("No tls configuration"));
-    }
-
-    public boolean isEnableCORS() {
-        return enableCORS;
-    }
-
-    public boolean isTlsEnabled() {
-        return tlsConfiguration.isPresent();
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof WebAdminConfiguration) {
-            WebAdminConfiguration that = (WebAdminConfiguration) o;
-
-            return Objects.equals(this.enabled, that.enabled)
-                && Objects.equals(this.port, that.port)
-                && Objects.equals(this.tlsConfiguration, that.tlsConfiguration)
-                && Objects.equals(this.enableCORS, that.enableCORS)
-                && Objects.equals(this.urlCORSOrigin, that.urlCORSOrigin);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(enabled, port, tlsConfiguration, enableCORS, urlCORSOrigin);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminServer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminServer.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminServer.java
deleted file mode 100644
index abce524..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/WebAdminServer.java
+++ /dev/null
@@ -1,129 +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.webadmin;
-
-import java.io.IOException;
-import java.util.Set;
-
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.HierarchicalConfiguration;
-import org.apache.james.lifecycle.api.Configurable;
-import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.webadmin.authentication.AuthenticationFilter;
-import org.apache.james.webadmin.authentication.NoAuthenticationFilter;
-import org.apache.james.webadmin.metric.MetricPostFilter;
-import org.apache.james.webadmin.metric.MetricPreFilter;
-import org.apache.james.webadmin.routes.CORSRoute;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-
-import spark.Service;
-
-public class WebAdminServer implements Configurable {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(WebAdminServer.class);
-    public static final HierarchicalConfiguration NO_CONFIGURATION = null;
-    public static final int DEFAULT_PORT = 8080;
-
-    private final WebAdminConfiguration configuration;
-    private final Set<Routes> routesList;
-    private final Service service;
-    private final AuthenticationFilter authenticationFilter;
-    private final MetricFactory metricFactory;
-
-    // Spark do not allow to retrieve allocated port when using a random port. Thus we generate the port.
-    @Inject
-    private WebAdminServer(WebAdminConfiguration configuration, Set<Routes> routesList, AuthenticationFilter authenticationFilter,
-                           MetricFactory metricFactory) {
-        this.configuration = configuration;
-        this.routesList = routesList;
-        this.authenticationFilter = authenticationFilter;
-        this.metricFactory = metricFactory;
-        this.service = Service.ignite();
-    }
-
-    @VisibleForTesting
-    public WebAdminServer(MetricFactory metricFactory, Routes... routes) throws IOException {
-        this(WebAdminConfiguration.testingConfiguration(),
-            ImmutableSet.copyOf(routes),
-            new NoAuthenticationFilter(),
-            metricFactory);
-    }
-
-    @Override
-    public void configure(HierarchicalConfiguration config) throws ConfigurationException {
-        if (configuration.isEnabled()) {
-            service.port(configuration.getPort().toInt());
-            configureHTTPS();
-            configureCORS();
-            configureMetrics();
-            service.before(authenticationFilter);
-            routesList.forEach(routes -> routes.define(service));
-            service.awaitInitialization();
-            LOGGER.info("Web admin server started");
-        }
-    }
-
-    private void configureMetrics() {
-        service.before(new MetricPreFilter(metricFactory));
-        service.after(new MetricPostFilter());
-    }
-
-    private void configureHTTPS() {
-        if (configuration.isTlsEnabled()) {
-            TlsConfiguration tlsConfiguration = configuration.getTlsConfiguration();
-            service.secure(tlsConfiguration.getKeystoreFilePath(),
-                tlsConfiguration.getKeystorePassword(),
-                tlsConfiguration.getTruststoreFilePath(),
-                tlsConfiguration.getTruststorePassword());
-            LOGGER.info("Web admin set up to use HTTPS");
-        }
-    }
-
-    private void configureCORS() {
-        if (configuration.isEnabled()) {
-            service.before(new CORSFilter(configuration.getUrlCORSOrigin()));
-            new CORSRoute().define(service);
-            LOGGER.info("Web admin set up to enable CORS from " + configuration.getUrlCORSOrigin());
-        }
-    }
-
-    @PreDestroy
-    public void destroy() {
-        if (configuration.isEnabled()) {
-            service.stop();
-            LOGGER.info("Web admin server stopped");
-        }
-    }
-
-    public void await() {
-        service.awaitInitialization();
-    }
-
-    public Port getPort() {
-        return configuration.getPort();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
deleted file mode 100644
index f73b818..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/AuthenticationFilter.java
+++ /dev/null
@@ -1,25 +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.webadmin.authentication;
-
-import spark.Filter;
-
-public interface AuthenticationFilter extends Filter {
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
deleted file mode 100644
index 4832d6f..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/JwtFilter.java
+++ /dev/null
@@ -1,76 +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.webadmin.authentication;
-
-import static spark.Spark.halt;
-
-import java.util.Optional;
-
-import javax.inject.Inject;
-
-import org.apache.james.jwt.JwtTokenVerifier;
-
-import spark.Request;
-import spark.Response;
-
-public class JwtFilter implements AuthenticationFilter {
-    public static final String AUTHORIZATION_HEADER_PREFIX = "Bearer ";
-    public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
-    public static final String OPTIONS = "OPTIONS";
-
-    private final JwtTokenVerifier jwtTokenVerifier;
-
-    @Inject
-    public JwtFilter(JwtTokenVerifier jwtTokenVerifier) {
-        this.jwtTokenVerifier = jwtTokenVerifier;
-    }
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-        if (request.requestMethod() != OPTIONS) {
-            Optional<String> bearer = Optional.ofNullable(request.headers(AUTHORIZATION_HEADER_NAME))
-                .filter(value -> value.startsWith(AUTHORIZATION_HEADER_PREFIX))
-                .map(value -> value.substring(AUTHORIZATION_HEADER_PREFIX.length()));
-
-            checkHeaderPresent(bearer);
-            checkValidSignature(bearer);
-            checkIsAdmin(bearer);
-        }
-    }
-
-    private void checkHeaderPresent(Optional<String> bearer) {
-        if (!bearer.isPresent()) {
-            halt(401, "No Bearer header.");
-        }
-    }
-
-    private void checkValidSignature(Optional<String> bearer) {
-        if (!jwtTokenVerifier.verify(bearer.get())) {
-            halt(401, "Invalid Bearer header.");
-        }
-    }
-
-    private void checkIsAdmin(Optional<String> bearer) {
-        if (!jwtTokenVerifier.hasAttribute("admin", true, bearer.get())) {
-            halt(401, "Non authorized user.");
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
deleted file mode 100644
index 45a2f5b..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/authentication/NoAuthenticationFilter.java
+++ /dev/null
@@ -1,31 +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.webadmin.authentication;
-
-import spark.Request;
-import spark.Response;
-
-public class NoAuthenticationFilter implements AuthenticationFilter {
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
deleted file mode 100644
index 1d102c2..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
+++ /dev/null
@@ -1,39 +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.webadmin.dto;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-
-public class AddUserRequest {
-
-    private final char[] password;
-
-    @JsonCreator
-    public AddUserRequest(@JsonProperty("password") char[] password) {
-        Preconditions.checkNotNull(password);
-        this.password = password;
-    }
-
-    public char[] getPassword() {
-        return password;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
deleted file mode 100644
index b552f45..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
+++ /dev/null
@@ -1,33 +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.webadmin.dto;
-
-public class MailboxResponse {
-
-    private final String mailboxName;
-
-    public MailboxResponse(String mailboxName) {
-        this.mailboxName = mailboxName;
-    }
-
-    public String getMailboxName() {
-        return mailboxName;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
deleted file mode 100644
index b3403ae..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
+++ /dev/null
@@ -1,73 +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.webadmin.dto;
-
-import org.apache.james.mailbox.model.Quota;
-
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
-import com.google.common.base.Preconditions;
-
-@JsonDeserialize(builder = QuotaDTO.Builder.class)
-public class QuotaDTO {
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    @JsonPOJOBuilder(withPrefix="")
-    public static class Builder {
-        private long count;
-        private long size;
-
-        public Builder count(long count) {
-            this.count = count;
-            return this;
-        }
-
-        public Builder size(long size) {
-            this.size = size;
-            return this;
-        }
-
-        public QuotaDTO build() {
-            return new QuotaDTO(count, size);
-        }
-
-    }
-
-    private final long count;
-    private final long size;
-
-    private QuotaDTO(long count, long size) {
-        Preconditions.checkArgument(count >= Quota.UNLIMITED);
-        Preconditions.checkArgument(size >= Quota.UNLIMITED);
-        this.count = count;
-        this.size = size;
-    }
-
-    public long getCount() {
-        return count;
-    }
-
-    public long getSize() {
-        return size;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
deleted file mode 100644
index 7ae9e85..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
+++ /dev/null
@@ -1,39 +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.webadmin.dto;
-
-import com.google.common.base.Preconditions;
-
-public class QuotaRequest {
-    public static QuotaRequest parse(String serialized) {
-        return new QuotaRequest(Long.valueOf(serialized));
-    }
-
-    private final long value;
-
-    public QuotaRequest(long value) {
-        Preconditions.checkArgument(value >= 0);
-        this.value = value;
-    }
-
-    public long getValue() {
-        return value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/UserResponse.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
deleted file mode 100644
index 5fe1846..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
+++ /dev/null
@@ -1,33 +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.webadmin.dto;
-
-public class UserResponse {
-
-    private final String username;
-
-    public UserResponse(String username) {
-        this.username = username;
-    }
-
-    public String getUsername() {
-        return username;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
deleted file mode 100644
index 4d9b8b7..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPostFilter.java
+++ /dev/null
@@ -1,37 +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.webadmin.metric;
-
-import org.apache.james.metrics.api.TimeMetric;
-
-import spark.Filter;
-import spark.Request;
-import spark.Response;
-
-public class MetricPostFilter implements Filter {
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-        if (request.attribute(MetricPreFilter.METRICS) instanceof TimeMetric) {
-            TimeMetric timeMetric = request.attribute(MetricPreFilter.METRICS);
-            timeMetric.stopAndPublish();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
deleted file mode 100644
index 1ed9d76..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/metric/MetricPreFilter.java
+++ /dev/null
@@ -1,41 +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.webadmin.metric;
-
-import org.apache.james.metrics.api.MetricFactory;
-
-import spark.Filter;
-import spark.Request;
-import spark.Response;
-
-public class MetricPreFilter implements Filter {
-    public static final String METRICS = "metrics";
-    private final MetricFactory metricFactory;
-
-    public MetricPreFilter(MetricFactory metricFactory) {
-        this.metricFactory = metricFactory;
-    }
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-        request.attribute(METRICS, metricFactory.timer("webAdmin"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
deleted file mode 100644
index 39e9bd7..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/CORSRoute.java
+++ /dev/null
@@ -1,42 +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.webadmin.routes;
-
-import org.apache.james.webadmin.Routes;
-
-import spark.Service;
-
-public class CORSRoute implements Routes {
-
-    @Override
-    public void define(Service service) {
-        service.options("/*", (request, response) -> {
-            String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
-            if (accessControlRequestHeaders != null) {
-                response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
-            }
-            String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
-            if (accessControlRequestMethod != null) {
-                response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
-            }
-            return "";
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
deleted file mode 100644
index 2008278..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
+++ /dev/null
@@ -1,118 +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.webadmin.routes;
-
-import static org.apache.james.webadmin.Constants.SEPARATOR;
-
-import javax.inject.Inject;
-
-import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.domainlist.api.DomainListException;
-import org.apache.james.webadmin.Constants;
-import org.apache.james.webadmin.Routes;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-
-import spark.Request;
-import spark.Response;
-import spark.Service;
-
-public class DomainRoutes implements Routes {
-
-    private static final String DOMAIN_NAME = ":domainName";
-    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutes.class);
-
-    public static final String DOMAINS = "/domains";
-    public static final String SPECIFIC_DOMAIN = DOMAINS + SEPARATOR + DOMAIN_NAME;
-    public static final int MAXIMUM_DOMAIN_SIZE = 256;
-
-
-    private final DomainList domainList;
-    private final JsonTransformer jsonTransformer;
-
-    @Inject
-    public DomainRoutes(DomainList domainList, JsonTransformer jsonTransformer) {
-        this.domainList = domainList;
-        this.jsonTransformer = jsonTransformer;
-    }
-
-    @Override
-    public void define(Service service) {
-        service.get(DOMAINS,
-            (request, response) -> domainList.getDomains(),
-            jsonTransformer);
-
-        service.get(SPECIFIC_DOMAIN, this::exists);
-
-        service.put(SPECIFIC_DOMAIN, this::addDomain);
-
-        service.delete(SPECIFIC_DOMAIN, this::removeDomain);
-    }
-
-    private String removeDomain(Request request, Response response) {
-        try {
-            String domain = request.params(DOMAIN_NAME);
-            removeDomain(domain);
-        } catch (DomainListException e) {
-            LOGGER.info("{} did not exists", request.params(DOMAIN_NAME));
-        }
-        response.status(204);
-        return Constants.EMPTY_BODY;
-    }
-
-    private void removeDomain(String domain) throws DomainListException {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
-        domainList.removeDomain(domain);
-    }
-
-    private String addDomain(Request request, Response response) {
-        try {
-            addDomain(request.params(DOMAIN_NAME));
-            response.status(204);
-        } catch (DomainListException e) {
-            LOGGER.info("{} already exists", request.params(DOMAIN_NAME));
-            response.status(204);
-        } catch (IllegalArgumentException e) {
-            LOGGER.info("Invalid request for domain creation");
-            response.status(400);
-        }
-        return Constants.EMPTY_BODY;
-    }
-
-    private void addDomain(String domain) throws DomainListException {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
-        Preconditions.checkArgument(!domain.contains("@"));
-        Preconditions.checkArgument(domain.length() < MAXIMUM_DOMAIN_SIZE);
-        domainList.addDomain(domain);
-    }
-
-    private String exists(Request request, Response response) throws DomainListException {
-        if (!domainList.containsDomain(request.params(DOMAIN_NAME))) {
-            response.status(404);
-        } else {
-            response.status(204);
-        }
-        return Constants.EMPTY_BODY;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
deleted file mode 100644
index eeca83a..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
+++ /dev/null
@@ -1,130 +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.webadmin.routes;
-
-import javax.inject.Inject;
-
-import org.apache.james.mailbox.model.Quota;
-import org.apache.james.mailbox.quota.MaxQuotaManager;
-import org.apache.james.webadmin.Constants;
-import org.apache.james.webadmin.Routes;
-import org.apache.james.webadmin.dto.QuotaDTO;
-import org.apache.james.webadmin.dto.QuotaRequest;
-import org.apache.james.webadmin.utils.JsonExtractException;
-import org.apache.james.webadmin.utils.JsonExtractor;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import spark.Service;
-
-public class GlobalQuotaRoutes implements Routes {
-
-    public static final String QUOTA_ENDPOINT = "/quota";
-    public static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
-    public static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
-    private static final Logger LOGGER = LoggerFactory.getLogger(Routes.class);
-
-    private final MaxQuotaManager maxQuotaManager;
-    private final JsonTransformer jsonTransformer;
-    private final JsonExtractor<QuotaDTO> jsonExtractor;
-
-    @Inject
-    public GlobalQuotaRoutes(MaxQuotaManager maxQuotaManager, JsonTransformer jsonTransformer) {
-        this.maxQuotaManager = maxQuotaManager;
-        this.jsonTransformer = jsonTransformer;
-        this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class);
-    }
-
-    @Override
-    public void define(Service service) {
-        service.get(COUNT_ENDPOINT, (request, response) -> {
-            long value = maxQuotaManager.getDefaultMaxMessage();
-            response.status(200);
-            return value;
-        }, jsonTransformer);
-
-        service.delete(COUNT_ENDPOINT, (request, response) -> {
-            maxQuotaManager.setDefaultMaxMessage(Quota.UNLIMITED);
-            response.status(204);
-            return Constants.EMPTY_BODY;
-        });
-
-        service.put(COUNT_ENDPOINT, (request, response) -> {
-            try {
-                QuotaRequest quotaRequest = QuotaRequest.parse(request.body());
-                maxQuotaManager.setDefaultMaxMessage(quotaRequest.getValue());
-                response.status(204);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Invalid quota. Need to be an integer value greater than 0");
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.get(SIZE_ENDPOINT, (request, response) -> {
-            long value = maxQuotaManager.getDefaultMaxStorage();
-            response.status(200);
-            return value;
-        }, jsonTransformer);
-
-        service.delete(SIZE_ENDPOINT, (request, response) -> {
-            maxQuotaManager.setDefaultMaxStorage(Quota.UNLIMITED);
-            response.status(204);
-            return Constants.EMPTY_BODY;
-        });
-
-        service.put(SIZE_ENDPOINT, (request, response) -> {
-            try {
-                QuotaRequest quotaRequest = QuotaRequest.parse(request.body());
-                maxQuotaManager.setDefaultMaxStorage(quotaRequest.getValue());
-                response.status(204);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Invalid quota. Need to be an integer value greater than 0");
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.get(QUOTA_ENDPOINT, (request, response) -> {
-            QuotaDTO quotaDTO = QuotaDTO.builder()
-                .count(maxQuotaManager.getDefaultMaxMessage())
-                .size(maxQuotaManager.getDefaultMaxStorage()).build();
-            response.status(200);
-            return quotaDTO;
-        }, jsonTransformer);
-
-        service.put(QUOTA_ENDPOINT, ((request, response) -> {
-            try {
-                QuotaDTO quotaDTO = jsonExtractor.parse(request.body());
-                maxQuotaManager.setDefaultMaxMessage(quotaDTO.getCount());
-                maxQuotaManager.setDefaultMaxStorage(quotaDTO.getSize());
-                response.status(204);
-            } catch (JsonExtractException e) {
-                LOGGER.info("Malformed JSON", e);
-                response.status(400);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Quota should be positive or unlimited (-1)", e);
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        }));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
deleted file mode 100644
index 717ef2b..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java
+++ /dev/null
@@ -1,128 +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.webadmin.routes;
-
-import javax.inject.Inject;
-
-import org.apache.james.webadmin.Constants;
-import org.apache.james.webadmin.Routes;
-import org.apache.james.webadmin.service.UserMailboxesService;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.apache.james.webadmin.utils.MailboxHaveChildrenException;
-import org.apache.james.webadmin.validation.MailboxName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import spark.Service;
-
-public class UserMailboxesRoutes implements Routes {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesRoutes.class);
-
-    public static final String MAILBOX_NAME = ":mailboxName";
-    public static final String MAILBOXES = "mailboxes";
-    private static final String USER_NAME = ":userName";
-    public static final String USER_MAILBOXES_BASE = UserRoutes.USERS + Constants.SEPARATOR + USER_NAME + Constants.SEPARATOR + MAILBOXES;
-    public static final String SPECIFIC_MAILBOX = USER_MAILBOXES_BASE + Constants.SEPARATOR + MAILBOX_NAME;
-
-    private final UserMailboxesService userMailboxesService;
-    private final JsonTransformer jsonTransformer;
-
-    @Inject
-    public UserMailboxesRoutes(UserMailboxesService userMailboxesService, JsonTransformer jsonTransformer) {
-        this.userMailboxesService = userMailboxesService;
-        this.jsonTransformer = jsonTransformer;
-    }
-
-    @Override
-    public void define(Service service) {
-
-        service.put(SPECIFIC_MAILBOX, (request, response) -> {
-            try {
-                userMailboxesService.createMailbox(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)));
-                response.status(204);
-            } catch (IllegalStateException e) {
-                LOGGER.info("Invalid put on user mailbox", e);
-                response.status(404);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Attempt to create an invalid mailbox");
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.delete(SPECIFIC_MAILBOX, (request, response) -> {
-            try {
-                userMailboxesService.deleteMailbox(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)));
-                response.status(204);
-            } catch (IllegalStateException e) {
-                LOGGER.info("Invalid delete on user mailbox", e);
-                response.status(404);
-            } catch (MailboxHaveChildrenException e) {
-                LOGGER.info("Attempt to delete a mailbox with children");
-                response.status(409);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Attempt to create an invalid mailbox");
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.delete(USER_MAILBOXES_BASE, (request, response) -> {
-            try {
-                userMailboxesService.deleteMailboxes(request.params(USER_NAME));
-                response.status(204);
-            } catch (IllegalStateException e) {
-                LOGGER.info("Invalid delete on user mailboxes", e);
-                response.status(404);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.get(SPECIFIC_MAILBOX, (request, response) -> {
-            try {
-                if (userMailboxesService.testMailboxExists(request.params(USER_NAME), new MailboxName(request.params(MAILBOX_NAME)))) {
-                    response.status(204);
-                } else {
-                    response.status(404);
-                }
-            } catch (IllegalStateException e) {
-                LOGGER.info("Invalid get on user mailbox", e);
-                response.status(404);
-            } catch (IllegalArgumentException e) {
-                LOGGER.info("Attempt to create an invalid mailbox");
-                response.status(400);
-            }
-            return Constants.EMPTY_BODY;
-        });
-
-        service.get(USER_MAILBOXES_BASE, (request, response) -> {
-            response.status(200);
-            try {
-                return userMailboxesService.listMailboxes(request.params(USER_NAME));
-            } catch (IllegalStateException e) {
-                LOGGER.info("Invalid get on user mailboxes", e);
-                response.status(404);
-                return Constants.EMPTY_BODY;
-            }
-        }, jsonTransformer);
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
deleted file mode 100644
index 0ead90a..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
+++ /dev/null
@@ -1,104 +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.webadmin.routes;
-
-import static org.apache.james.webadmin.Constants.SEPARATOR;
-
-import javax.inject.Inject;
-
-import org.apache.james.user.api.UsersRepositoryException;
-import org.apache.james.webadmin.Constants;
-import org.apache.james.webadmin.Routes;
-import org.apache.james.webadmin.dto.AddUserRequest;
-import org.apache.james.webadmin.service.UserService;
-import org.apache.james.webadmin.utils.JsonExtractException;
-import org.apache.james.webadmin.utils.JsonExtractor;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import spark.Request;
-import spark.Response;
-import spark.Service;
-
-public class UserRoutes implements Routes {
-
-    private static final String USER_NAME = ":userName";
-    private static final Logger LOGGER = LoggerFactory.getLogger(UserRoutes.class);
-
-    public static final String USERS = "/users";
-
-    private final UserService userService;
-    private final JsonTransformer jsonTransformer;
-    private final JsonExtractor<AddUserRequest> jsonExtractor;
-
-    @Inject
-    public UserRoutes(UserService userService, JsonTransformer jsonTransformer) {
-        this.userService = userService;
-        this.jsonTransformer = jsonTransformer;
-        this.jsonExtractor = new JsonExtractor<>(AddUserRequest.class);
-    }
-
-    @Override
-    public void define(Service service) {
-        service.get(USERS,
-            (request, response) -> userService.getUsers(),
-            jsonTransformer);
-
-        service.put(USERS + SEPARATOR + USER_NAME, this::upsertUser);
-
-        service.delete(USERS + SEPARATOR + USER_NAME, this::removeUser);
-    }
-
-    private String removeUser(Request request, Response response) {
-        String username = request.params(USER_NAME);
-        try {
-            userService.removeUser(username);
-            response.status(204);
-            return Constants.EMPTY_BODY;
-        } catch (UsersRepositoryException e) {
-            response.status(204);
-            return "The user " + username + " does not exists";
-        } catch (IllegalArgumentException e) {
-            LOGGER.info("Invalid user path", e);
-            response.status(400);
-            return Constants.EMPTY_BODY;
-        }
-    }
-
-    private String upsertUser(Request request, Response response) throws UsersRepositoryException {
-        try {
-            return userService.upsertUser(request.params(USER_NAME),
-                jsonExtractor.parse(request.body()).getPassword(),
-                response);
-        } catch (JsonExtractException e) {
-            LOGGER.info("Error while deserializing addUser request", e);
-            response.status(400);
-            return Constants.EMPTY_BODY;
-        } catch (IllegalArgumentException e) {
-            LOGGER.info("Invalid user path", e);
-            response.status(400);
-            return Constants.EMPTY_BODY;
-        }
-    }
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
deleted file mode 100644
index 469bdfb..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
+++ /dev/null
@@ -1,143 +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.webadmin.service;
-
-import java.util.List;
-import java.util.stream.Stream;
-
-import javax.inject.Inject;
-
-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.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.model.MailboxMetaData;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.MailboxQuery;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.api.UsersRepositoryException;
-import org.apache.james.webadmin.dto.MailboxResponse;
-import org.apache.james.webadmin.utils.MailboxHaveChildrenException;
-import org.apache.james.webadmin.validation.MailboxName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.fge.lambdas.Throwing;
-import com.github.steveash.guavate.Guavate;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-
-
-public class UserMailboxesService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesService.class);
-    private static final String USER_NAME = "webAdmin";
-
-    private final MailboxManager mailboxManager;
-    private final UsersRepository usersRepository;
-
-    @Inject
-    public UserMailboxesService(MailboxManager mailboxManager, UsersRepository usersRepository) {
-        this.mailboxManager = mailboxManager;
-        this.usersRepository = usersRepository;
-    }
-
-    public void createMailbox(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException {
-        usernamePreconditions(username);
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
-        try {
-            mailboxManager.createMailbox(
-                convertToMailboxPath(username, mailboxName.asString(), mailboxSession),
-                mailboxSession);
-        } catch (MailboxExistsException e) {
-            LOGGER.info("Attempt to create mailbox {} for user {} that already exists", mailboxName, username);
-        }
-    }
-
-    public void deleteMailboxes(String username) throws MailboxException, UsersRepositoryException {
-        usernamePreconditions(username);
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
-        listUserMailboxes(username, mailboxSession)
-            .map(MailboxMetaData::getPath)
-            .forEach(Throwing.consumer(mailboxPath -> deleteMailbox(mailboxSession, mailboxPath)));
-    }
-
-    public List<MailboxResponse> listMailboxes(String username) throws MailboxException, UsersRepositoryException {
-        usernamePreconditions(username);
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
-        return listUserMailboxes(username, mailboxSession)
-            .map(mailboxMetaData -> new MailboxResponse(mailboxMetaData.getPath().getName()))
-            .collect(Guavate.toImmutableList());
-    }
-
-    public boolean testMailboxExists(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException {
-        usernamePreconditions(username);
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
-        return mailboxManager.mailboxExists(
-            convertToMailboxPath(username, mailboxName.asString(), mailboxSession),
-            mailboxSession);
-    }
-
-    public void deleteMailbox(String username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException {
-        usernamePreconditions(username);
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(USER_NAME, LOGGER);
-        MailboxPath mailboxPath = convertToMailboxPath(username, mailboxName.asString(), mailboxSession);
-        listChildren(mailboxPath, mailboxSession)
-            .forEach(Throwing.consumer(path -> deleteMailbox(mailboxSession, path)));
-    }
-
-    private Stream<MailboxPath> listChildren(MailboxPath mailboxPath, MailboxSession mailboxSession) throws MailboxException {
-        return mailboxManager.search(createUserMailboxesQuery(mailboxPath.getUser()), mailboxSession)
-            .stream()
-            .map(MailboxMetaData::getPath)
-            .filter(path -> path.getHierarchyLevels(mailboxSession.getPathDelimiter()).contains(mailboxPath));
-    }
-
-    private void deleteMailbox(MailboxSession mailboxSession, MailboxPath mailboxPath) throws MailboxException {
-        try {
-            mailboxManager.deleteMailbox(mailboxPath, mailboxSession);
-        } catch (MailboxNotFoundException e) {
-            LOGGER.info("Attempt to delete mailbox {} for user {} that does not exists", mailboxPath.getName(), mailboxPath.getUser());
-        }
-    }
-
-    private void usernamePreconditions(String username) throws UsersRepositoryException {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(username));
-        Preconditions.checkState(usersRepository.contains(username));
-    }
-
-    private MailboxPath convertToMailboxPath(String username, String mailboxName, MailboxSession mailboxSession) {
-        return new MailboxPath(mailboxSession.getPersonalSpace(), username, mailboxName);
-    }
-
-    private Stream<MailboxMetaData> listUserMailboxes(String username, MailboxSession mailboxSession) throws MailboxException {
-        return mailboxManager.search(createUserMailboxesQuery(username), mailboxSession)
-            .stream();
-    }
-
-    private MailboxQuery createUserMailboxesQuery(String username) {
-        return MailboxQuery.builder()
-            .username(username)
-            .privateUserMailboxes()
-            .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserService.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserService.java
deleted file mode 100644
index ee0952d..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/service/UserService.java
+++ /dev/null
@@ -1,94 +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.webadmin.service;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import javax.inject.Inject;
-
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.api.UsersRepositoryException;
-import org.apache.james.user.api.model.User;
-import org.apache.james.util.streams.Iterators;
-import org.apache.james.webadmin.dto.UserResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-
-import spark.Response;
-
-public class UserService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
-    private static final String EMPTY_BODY = "";
-    public static final int MAXIMUM_MAIL_ADDRESS_LENGTH = 255;
-
-    private final UsersRepository usersRepository;
-
-    @Inject
-    public UserService(UsersRepository usersRepository) {
-        this.usersRepository = usersRepository;
-    }
-
-    public List<UserResponse> getUsers() throws UsersRepositoryException {
-        return  Optional.ofNullable(usersRepository.list())
-            .map(Iterators::toStream)
-            .orElse(Stream.of())
-            .map(UserResponse::new)
-            .collect(Guavate.toImmutableList());
-    }
-
-    public void removeUser(String username) throws UsersRepositoryException {
-        usernamePreconditions(username);
-        usersRepository.removeUser(username);
-    }
-
-    public String upsertUser(String username, char[] password, Response response) throws UsersRepositoryException {
-        usernamePreconditions(username);
-        User user = usersRepository.getUserByName(username);
-        try {
-            upsert(user, username, password);
-            response.status(204);
-        } catch (UsersRepositoryException e) {
-            LOGGER.info("Error creating or updating user : {}", e.getMessage());
-            response.status(409);
-        }
-        return EMPTY_BODY;
-    }
-
-    private void usernamePreconditions(String username) {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(username));
-        Preconditions.checkArgument(username.length() < MAXIMUM_MAIL_ADDRESS_LENGTH);
-    }
-
-    private void upsert(User user, String username, char[] password) throws UsersRepositoryException {
-        if (user == null) {
-            usersRepository.addUser(username, new String(password));
-        } else {
-            user.setPassword(new String(password));
-            usersRepository.updateUser(user);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java
deleted file mode 100644
index dc6b578..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractException.java
+++ /dev/null
@@ -1,27 +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.webadmin.utils;
-
-public class JsonExtractException extends Exception {
-
-    public JsonExtractException(Throwable throwable) {
-        super(throwable);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
deleted file mode 100644
index f4eb420..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
+++ /dev/null
@@ -1,44 +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.webadmin.utils;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public class JsonExtractor<Request> {
-
-    private final ObjectMapper objectMapper;
-    private final Class<Request> type;
-
-    public JsonExtractor(Class<Request> type) {
-        this.objectMapper = new ObjectMapper();
-        this.type = type;
-    }
-
-    public Request parse(String text) throws JsonExtractException {
-        try {
-            return objectMapper.readValue(text, type);
-        } catch (IOException e) {
-            throw new JsonExtractException(e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
deleted file mode 100644
index 3c32f0c..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
+++ /dev/null
@@ -1,41 +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.webadmin.utils;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-
-import spark.ResponseTransformer;
-
-public class JsonTransformer implements ResponseTransformer {
-
-    private final ObjectMapper objectMapper;
-
-    public JsonTransformer() {
-        objectMapper = new ObjectMapper();
-        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
-    }
-
-    @Override
-    public String render(Object o) throws JsonProcessingException {
-        return objectMapper.writeValueAsString(o);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java
deleted file mode 100644
index ae8213e..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/MailboxHaveChildrenException.java
+++ /dev/null
@@ -1,27 +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.webadmin.utils;
-
-public class MailboxHaveChildrenException extends Exception {
-
-    public MailboxHaveChildrenException(String mailboxName) {
-        super(mailboxName + "have children");
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/validation/MailboxName.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
deleted file mode 100644
index fdd079d..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/validation/MailboxName.java
+++ /dev/null
@@ -1,40 +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.webadmin.validation;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-
-public class MailboxName {
-
-    public static final CharMatcher INVALID_CHARS_MATCHER = CharMatcher.anyOf("%*&#");
-    private final String mailboxName;
-
-    public MailboxName(String mailboxName) {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(mailboxName));
-        Preconditions.checkArgument(INVALID_CHARS_MATCHER.matchesNoneOf(mailboxName));
-        this.mailboxName = mailboxName;
-    }
-
-    public String asString() {
-        return mailboxName;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/FixedPortTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/FixedPortTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/FixedPortTest.java
deleted file mode 100644
index 2712daa..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/FixedPortTest.java
+++ /dev/null
@@ -1,57 +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.webadmin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.junit.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class FixedPortTest {
-
-    @Test
-    public void toIntShouldThrowOnNegativePort() {
-        assertThatThrownBy(() -> new FixedPort(-1)).isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void toIntShouldThrowOnNullPort() {
-        assertThatThrownBy(() -> new FixedPort(0)).isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void toIntShouldThrowOnTooBigNumbers() {
-        assertThatThrownBy(() -> new FixedPort(65536)).isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void toIntShouldReturnedDesiredPort() {
-        int expectedPort = 452;
-        assertThat(new FixedPort(expectedPort).toInt()).isEqualTo(expectedPort);
-    }
-
-    @Test
-    public void shouldMatchBeanContract() {
-        EqualsVerifier.forClass(FixedPort.class).verify();
-    }
-
-}


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


[4/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/RandomPortTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/RandomPortTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/RandomPortTest.java
deleted file mode 100644
index 07d1996..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/RandomPortTest.java
+++ /dev/null
@@ -1,34 +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.webadmin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Test;
-
-public class RandomPortTest {
-
-    @Test
-    public void toIntShouldReturnTwoTimeTheSameResult() {
-        RandomPort testee = new RandomPort();
-        assertThat(testee.toInt()).isEqualTo(testee.toInt());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
deleted file mode 100644
index 2d93282..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/TlsConfigurationTest.java
+++ /dev/null
@@ -1,88 +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.webadmin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class TlsConfigurationTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void buildShouldThrowWhenNotEnabled() {
-        expectedException.expect(IllegalStateException.class);
-
-        TlsConfiguration.builder().build();
-    }
-
-    @Test
-    public void buildShouldThrowWhenEnableWithoutKeystore() {
-        expectedException.expect(IllegalStateException.class);
-
-        TlsConfiguration.builder().build();
-    }
-
-    @Test
-    public void selfSignedShouldThrowOnNullKeyStorePath() {
-        expectedException.expect(NullPointerException.class);
-
-        TlsConfiguration.builder()
-            .selfSigned(null, "abc");
-    }
-
-    @Test
-    public void selfSignedShouldThrowOnNullKeyStorePassword() {
-        expectedException.expect(NullPointerException.class);
-
-        TlsConfiguration.builder()
-            .selfSigned("abc", null);
-    }
-
-    @Test
-    public void buildShouldWorkOnSelfSignedHttps() {
-        assertThat(
-            TlsConfiguration.builder()
-                .selfSigned("abcd", "efgh")
-                .build())
-            .isEqualTo(new TlsConfiguration("abcd", "efgh", null, null));
-    }
-
-    @Test
-    public void buildShouldWorkOnTrustedHttps() {
-        assertThat(
-            TlsConfiguration.builder()
-                .raw("a", "b", "c", "d")
-                .build())
-            .isEqualTo(new TlsConfiguration("a", "b", "c", "d"));
-    }
-
-    @Test
-    public void shouldRespectBeanContract() {
-        EqualsVerifier.forClass(TlsConfiguration.class).verify();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
deleted file mode 100644
index 1030dcf..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java
+++ /dev/null
@@ -1,181 +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.webadmin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class WebAdminConfigurationTest {
-
-    public static final FixedPort PORT = new FixedPort(80);
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void buildShouldThrowWhenNoPortButEnabled() {
-        expectedException.expect(IllegalStateException.class);
-
-        WebAdminConfiguration.builder().enabled().build();
-    }
-
-    @Test
-    public void buildShouldWorkWithoutPortWhenDisabled() {
-        assertThat(WebAdminConfiguration.builder()
-            .disabled()
-            .build())
-            .extracting(WebAdminConfiguration::isEnabled)
-            .containsExactly(false);
-    }
-
-    @Test
-    public void buildShouldFailOnNoEnable() {
-        expectedException.expect(IllegalStateException.class);
-
-        WebAdminConfiguration.builder().port(PORT).build();
-    }
-
-    @Test
-    public void builderShouldBuildWithRightPort() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .build())
-            .extracting(WebAdminConfiguration::getPort)
-            .containsExactly(PORT);
-    }
-
-
-    @Test
-    public void builderShouldBuildWithEnable() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .build())
-            .extracting(WebAdminConfiguration::isEnabled)
-            .containsExactly(true);
-    }
-
-    @Test
-    public void builderShouldAcceptHttps() {
-        TlsConfiguration tlsConfiguration = TlsConfiguration.builder()
-            .selfSigned("abcd", "efgh")
-            .build();
-
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .tls(tlsConfiguration)
-                .port(PORT)
-                .build())
-            .extracting(WebAdminConfiguration::getTlsConfiguration)
-            .containsExactly(tlsConfiguration);
-    }
-
-    @Test
-    public void builderShouldReturnTlsEnableWhenTlsConfiguration() {
-        TlsConfiguration tlsConfiguration = TlsConfiguration.builder()
-            .selfSigned("abcd", "efgh")
-            .build();
-
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .tls(tlsConfiguration)
-                .port(PORT)
-                .build())
-            .extracting(WebAdminConfiguration::getTlsConfiguration)
-            .containsExactly(tlsConfiguration);
-    }
-
-    @Test
-    public void builderShouldReturnTlsDisableWhenNoTlsConfiguration() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .build())
-            .extracting(WebAdminConfiguration::isTlsEnabled)
-            .containsExactly(false);
-    }
-
-    @Test
-    public void builderShouldCORSEnabled() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .CORSenabled()
-                .build())
-            .extracting(WebAdminConfiguration::isEnableCORS)
-            .containsExactly(true);
-    }
-
-    @Test
-    public void builderShouldAcceptAllOriginsByDefault() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .CORSenabled()
-                .build())
-            .extracting(WebAdminConfiguration::getUrlCORSOrigin)
-            .containsExactly("*");
-    }
-
-    @Test
-    public void builderShouldCORSDisabled() {
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .CORSdisabled()
-                .build())
-            .extracting(WebAdminConfiguration::isEnableCORS)
-            .containsExactly(false);
-    }
-
-    @Test
-    public void builderShouldCORSWithOrigin() {
-        String origin = "linagora.com";
-        assertThat(
-            WebAdminConfiguration.builder()
-                .enabled()
-                .port(PORT)
-                .CORSenabled()
-                .urlCORSOrigin(origin)
-                .build())
-            .extracting(WebAdminConfiguration::getUrlCORSOrigin)
-            .containsExactly(origin);
-    }
-
-    @Test
-    public void shouldMatchBeanContract() {
-        EqualsVerifier.forClass(WebAdminConfiguration.class).verify();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
deleted file mode 100644
index 6512ddb..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/authentication/JwtFilterTest.java
+++ /dev/null
@@ -1,124 +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.webadmin.authentication;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.apache.james.jwt.JwtTokenVerifier;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import com.google.common.collect.ImmutableSet;
-
-import spark.HaltException;
-import spark.Request;
-import spark.Response;
-
-public class JwtFilterTest {
-
-    public static final Matcher<HaltException> STATUS_CODE_MATCHER_401 = new BaseMatcher<HaltException>() {
-        @Override
-        public boolean matches(Object o) {
-            if (o instanceof HaltException) {
-                HaltException haltException = (HaltException) o;
-                return haltException.statusCode() == 401;
-            }
-            return false;
-        }
-
-        @Override
-        public void describeTo(Description description) {}
-    };
-
-    private JwtTokenVerifier jwtTokenVerifier;
-    private JwtFilter jwtFilter;
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Before
-    public void setUp() {
-        jwtTokenVerifier = mock(JwtTokenVerifier.class);
-        jwtFilter = new JwtFilter(jwtTokenVerifier);
-    }
-
-    @Test
-    public void handleShouldRejectRequestWithHeaders() throws Exception {
-        Request request = mock(Request.class);
-        when(request.headers()).thenReturn(ImmutableSet.of());
-
-        expectedException.expect(HaltException.class);
-        expectedException.expect(STATUS_CODE_MATCHER_401);
-
-        jwtFilter.handle(request, mock(Response.class));
-    }
-
-    @Test
-    public void handleShouldRejectRequestWithBearersHeaders() throws Exception {
-        Request request = mock(Request.class);
-        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Invalid value");
-
-        expectedException.expect(HaltException.class);
-        expectedException.expect(STATUS_CODE_MATCHER_401);
-
-        jwtFilter.handle(request, mock(Response.class));
-    }
-
-    @Test
-    public void handleShouldRejectRequestWithInvalidBearerHeaders() throws Exception {
-        Request request = mock(Request.class);
-        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
-        when(jwtTokenVerifier.verify("value")).thenReturn(false);
-
-        expectedException.expect(HaltException.class);
-        expectedException.expect(STATUS_CODE_MATCHER_401);
-
-        jwtFilter.handle(request, mock(Response.class));
-    }
-
-    @Test
-    public void handleShouldRejectRequestWithoutAdminClaim() throws Exception {
-        Request request = mock(Request.class);
-        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
-        when(jwtTokenVerifier.verify("value")).thenReturn(true);
-        when(jwtTokenVerifier.hasAttribute("admin", true, "value")).thenReturn(false);
-
-        expectedException.expect(HaltException.class);
-        expectedException.expect(STATUS_CODE_MATCHER_401);
-
-        jwtFilter.handle(request, mock(Response.class));
-    }
-
-    @Test
-    public void handleShouldAcceptValidJwt() throws Exception {
-        Request request = mock(Request.class);
-        when(request.headers(JwtFilter.AUTHORIZATION_HEADER_NAME)).thenReturn("Bearer value");
-        when(jwtTokenVerifier.verify("value")).thenReturn(true);
-        when(jwtTokenVerifier.hasAttribute("admin", true, "value")).thenReturn(true);
-
-        jwtFilter.handle(request, mock(Response.class));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
deleted file mode 100644
index 34df209..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/dto/QuotaRequestTest.java
+++ /dev/null
@@ -1,59 +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.webadmin.dto;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class QuotaRequestTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void parseShouldThrowWhenNotANumber() {
-        expectedException.expect(NumberFormatException.class);
-
-        QuotaRequest.parse("invalid");
-    }
-
-    @Test
-    public void parseShouldThrowOnNegativeNumber() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        QuotaRequest.parse("-1");
-    }
-
-    @Test
-    public void parseShouldParseZero() {
-        assertThat(QuotaRequest.parse("0").getValue())
-            .isEqualTo(0);
-    }
-
-    @Test
-    public void parseShouldParsePositiveValue() {
-        assertThat(QuotaRequest.parse("42").getValue())
-            .isEqualTo(42);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
deleted file mode 100644
index 1df89d2..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
+++ /dev/null
@@ -1,326 +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.webadmin.routes;
-
-import static com.jayway.restassured.RestAssured.given;
-import static com.jayway.restassured.RestAssured.when;
-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.apache.james.webadmin.Constants.SEPARATOR;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.net.InetAddress;
-
-import org.apache.james.dnsservice.api.DNSService;
-import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.domainlist.api.DomainListException;
-import org.apache.james.domainlist.memory.MemoryDomainList;
-import org.apache.james.metrics.logger.DefaultMetricFactory;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Charsets;
-import com.jayway.restassured.RestAssured;
-import com.jayway.restassured.builder.RequestSpecBuilder;
-import com.jayway.restassured.http.ContentType;
-
-import de.bechte.junit.runners.context.HierarchicalContextRunner;
-
-@RunWith(HierarchicalContextRunner.class)
-public class DomainRoutesTest {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutesTest.class);
-    public static final String DOMAIN = "domain";
-
-    private WebAdminServer webAdminServer;
-
-    private void createServer(DomainList domainList) throws Exception {
-        webAdminServer = new WebAdminServer(
-            new DefaultMetricFactory(),
-            new DomainRoutes(domainList, new JsonTransformer()));
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = new RequestSpecBuilder()
-        		.setContentType(ContentType.JSON)
-        		.setAccept(ContentType.JSON)
-        		.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
-        		.setPort(webAdminServer.getPort().toInt())
-        		.setBasePath(DomainRoutes.DOMAINS)
-        		.build();
-
-    }
-
-    @After
-    public void stop() {
-        webAdminServer.destroy();
-    }
-
-    public class NormalBehaviour {
-
-        @Before
-        public void setUp() throws Exception {
-            DNSService dnsService = mock(DNSService.class);
-            when(dnsService.getHostName(any())).thenReturn("localhost");
-            when(dnsService.getLocalHost()).thenReturn(InetAddress.getByName("localhost"));
-
-            MemoryDomainList domainList = new MemoryDomainList();
-            domainList.setDNSService(dnsService);
-            domainList.setLog(LOGGER);
-            domainList.setAutoDetectIP(false);
-            createServer(domainList);
-        }
-
-        @Test
-        public void getDomainsShouldBeEmptyByDefault() {
-            given()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void putShouldReturnErrorWhenUsedWithEmptyDomain() {
-            given()
-                .put(SEPARATOR)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void deleteShouldReturnErrorWhenUsedWithEmptyDomain() {
-            given()
-                .delete(SEPARATOR)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldBeOk() {
-            given()
-                .put(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void getDomainsShouldDisplayAddedDomains() {
-            with()
-                .put(DOMAIN);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(containsString(DOMAIN));
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWhenNameContainsAT() {
-            when()
-                .put(DOMAIN + "@" + DOMAIN)
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWhenNameContainsUrlSeparator() {
-            when()
-                .put(DOMAIN + "/" + DOMAIN)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWhenNameIsTooLong() {
-            when()
-                .put(DOMAIN + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldWorkOnTheSecondTimeForAGivenValue() {
-            with()
-                .put(DOMAIN);
-
-            when()
-                .put(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldRemoveTheGivenDomain() {
-            with()
-                .put(DOMAIN);
-
-            when()
-                .delete(DOMAIN)
-            .then()
-                .statusCode(204);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void deleteShouldBeOkWhenTheDomainIsNotPresent() {
-            given()
-                .delete(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void getDomainShouldReturnOkWhenTheDomainIsPresent() {
-            with()
-                .put(DOMAIN);
-
-            when()
-                .get(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void getDomainShouldReturnNotFoundWhenTheDomainIsAbsent() {
-            given()
-                .get(DOMAIN)
-            .then()
-                .statusCode(404);
-        }
-
-    }
-
-    public class ExceptionHandling {
-
-        private DomainList domainList;
-        private String domain;
-
-        @Before
-        public void setUp() throws Exception {
-            domainList = mock(DomainList.class);
-            createServer(domainList);
-            domain = "domain";
-        }
-
-        @Test
-        public void deleteShouldReturnErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(domainList).removeDomain(domain);
-
-            when()
-                .delete(DOMAIN)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void putShouldReturnErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(domainList).addDomain(domain);
-
-            when()
-                .put(DOMAIN)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getDomainShouldReturnErrorOnUnknownException() throws Exception {
-            when(domainList.containsDomain(domain)).thenThrow(new RuntimeException());
-
-            when()
-                .get(DOMAIN)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getDomainsShouldReturnErrorOnUnknownException() throws Exception {
-            when(domainList.getDomains()).thenThrow(new RuntimeException());
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldReturnOkWhenDomainListException() throws Exception {
-            doThrow(new DomainListException("message")).when(domainList).removeDomain(domain);
-
-            when()
-                .delete(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void putShouldReturnOkWhenDomainListException() throws Exception {
-            doThrow(new DomainListException("message")).when(domainList).addDomain(domain);
-
-            when()
-                .put(DOMAIN)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void getDomainShouldReturnErrorOnDomainListException() throws Exception {
-            when(domainList.containsDomain(domain)).thenThrow(new DomainListException("message"));
-
-            when()
-                .get(DOMAIN)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getDomainsShouldReturnErrorOnDomainListException() throws Exception {
-            when(domainList.getDomains()).thenThrow(new DomainListException("message"));
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
deleted file mode 100644
index 16a9d3e..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
+++ /dev/null
@@ -1,261 +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.webadmin.routes;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static com.jayway.restassured.RestAssured.given;
-import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
-import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
-import static org.hamcrest.CoreMatchers.is;
-
-import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
-import org.apache.james.mailbox.model.Quota;
-import org.apache.james.metrics.logger.DefaultMetricFactory;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.common.base.Charsets;
-import com.jayway.restassured.RestAssured;
-import com.jayway.restassured.builder.RequestSpecBuilder;
-import com.jayway.restassured.http.ContentType;
-
-public class GlobalQuotaRoutesTest {
-
-    private WebAdminServer webAdminServer;
-    private InMemoryPerUserMaxQuotaManager maxQuotaManager;
-
-    @Before
-    public void setUp() throws Exception {
-        maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
-        webAdminServer = new WebAdminServer(
-            new DefaultMetricFactory(),
-            new GlobalQuotaRoutes(maxQuotaManager, new JsonTransformer()));
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = new RequestSpecBuilder()
-            .setContentType(ContentType.JSON)
-            .setAccept(ContentType.JSON)
-            .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
-            .setPort(webAdminServer.getPort().toInt())
-            .build();
-    }
-
-    @After
-    public void stop() {
-        webAdminServer.destroy();
-    }
-
-    @Test
-    public void getCountQuotaCountShouldReturnUnlimitedByDefault() {
-        given()
-            .get(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is(String.valueOf(Quota.UNLIMITED)));
-    }
-
-    @Test
-    public void getCountShouldReturnStoredValue() throws Exception{
-        int value = 42;
-        maxQuotaManager.setDefaultMaxMessage(value);
-
-        given()
-            .get(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is(String.valueOf(value)));
-    }
-
-    @Test
-    public void putCountShouldRejectInvalid() throws Exception {
-        given()
-            .body("invalid")
-            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(400);
-    }
-
-    @Test
-    public void putCountShouldRejectNegative() throws Exception {
-        given()
-            .body("-1")
-            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(400);
-    }
-
-    @Test
-    public void putCountShouldAcceptValidValue() throws Exception {
-        given()
-            .body("42")
-            .put(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(42);
-    }
-
-    @Test
-    public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setDefaultMaxMessage(42);
-
-        given()
-            .delete(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
-    }
-
-    @Test
-    public void getSizeQuotaCountShouldReturnUnlimitedByDefault() {
-        given()
-            .get(GlobalQuotaRoutes.SIZE_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is(String.valueOf(Quota.UNLIMITED)));
-    }
-
-    @Test
-    public void getSizeShouldReturnStoredValue() throws Exception{
-        int value = 42;
-        maxQuotaManager.setDefaultMaxStorage(value);
-
-        given()
-            .get(GlobalQuotaRoutes.SIZE_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is(String.valueOf(value)));
-    }
-
-    @Test
-    public void putSizeShouldRejectInvalid() throws Exception {
-        given()
-            .body("invalid")
-            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
-        .then()
-            .statusCode(400);
-    }
-
-    @Test
-    public void putSizeShouldRejectNegative() throws Exception {
-        given()
-            .body("-1")
-            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
-        .then()
-            .statusCode(400);
-    }
-
-    @Test
-    public void putSizeShouldAcceptValidValue() throws Exception {
-        given()
-            .body("42")
-            .put(GlobalQuotaRoutes.SIZE_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
-    }
-
-    @Test
-    public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
-        maxQuotaManager.setDefaultMaxStorage(42);
-
-        given()
-            .delete(GlobalQuotaRoutes.COUNT_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
-    }
-
-    @Test
-    public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
-        maxQuotaManager.setDefaultMaxStorage(42);
-        maxQuotaManager.setDefaultMaxMessage(52);
-
-        given()
-            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is("{\"count\":52,\"size\":42}"));
-    }
-
-    @Test
-    public void getQuotaShouldReturnBothDefaultValues() throws Exception {
-        given()
-            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is("{\"count\":-1,\"size\":-1}"));
-    }
-
-    @Test
-    public void getQuotaShouldReturnBothWhenNoCount() throws Exception {
-        maxQuotaManager.setDefaultMaxStorage(42);
-
-        given()
-            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is("{\"count\":-1,\"size\":42}"));
-    }
-
-    @Test
-    public void getQuotaShouldReturnBothWhenNoSize() throws Exception {
-        maxQuotaManager.setDefaultMaxMessage(42);
-
-        given()
-            .get(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(200)
-            .body(is("{\"count\":42,\"size\":-1}"));
-    }
-
-    @Test
-    public void putQuotaShouldUpdateBothQuota() throws Exception {
-        given()
-            .body("{\"count\":52,\"size\":42}")
-            .put(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(52);
-        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(42);
-    }
-
-    @Test
-    public void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
-        given()
-            .body("{\"count\":-1,\"size\":-1}")
-            .put(GlobalQuotaRoutes.QUOTA_ENDPOINT)
-        .then()
-            .statusCode(204);
-
-        assertThat(maxQuotaManager.getDefaultMaxMessage()).isEqualTo(Quota.UNLIMITED);
-        assertThat(maxQuotaManager.getDefaultMaxStorage()).isEqualTo(Quota.UNLIMITED);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
deleted file mode 100644
index 3db15b1..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
+++ /dev/null
@@ -1,779 +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.webadmin.routes;
-
-import static com.jayway.restassured.RestAssured.when;
-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.apache.james.webadmin.Constants.SEPARATOR;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
-import static org.hamcrest.CoreMatchers.is;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.apache.james.mailbox.MailboxManager;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
-import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.exception.MailboxException;
-import org.apache.james.mailbox.exception.MailboxExistsException;
-import org.apache.james.mailbox.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.inmemory.InMemoryId;
-import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
-import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.MailboxQuery;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.store.FakeAuthorizator;
-import org.apache.james.mailbox.store.JVMMailboxPathLocker;
-import org.apache.james.mailbox.store.SimpleMailboxMetaData;
-import org.apache.james.mailbox.store.mail.model.DefaultMessageId;
-import org.apache.james.mailbox.store.mail.model.impl.MessageParser;
-import org.apache.james.metrics.logger.DefaultMetricFactory;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.service.UserMailboxesService;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.jayway.restassured.RestAssured;
-import com.jayway.restassured.builder.RequestSpecBuilder;
-import com.jayway.restassured.http.ContentType;
-
-import de.bechte.junit.runners.context.HierarchicalContextRunner;
-
-@RunWith(HierarchicalContextRunner.class)
-public class UserMailboxesRoutesTest {
-
-    public static final String USERNAME = "username";
-    public static final String MAILBOX_NAME = "myMailboxName";
-    private WebAdminServer webAdminServer;
-    private UsersRepository usersRepository;
-
-    private void createServer(MailboxManager mailboxManager) throws Exception {
-        usersRepository = mock(UsersRepository.class);
-        when(usersRepository.contains(USERNAME)).thenReturn(true);
-
-        webAdminServer = new WebAdminServer(
-            new DefaultMetricFactory(),
-            new UserMailboxesRoutes(new UserMailboxesService(mailboxManager, usersRepository), new JsonTransformer()));
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = new RequestSpecBuilder()
-        		.setContentType(ContentType.JSON)
-        		.setAccept(ContentType.JSON)
-        		.setBasePath(UserRoutes.USERS + SEPARATOR + USERNAME + SEPARATOR + UserMailboxesRoutes.MAILBOXES)
-        		.setPort(webAdminServer.getPort().toInt())
-        		.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
-        		.build();
-    }
-
-    @After
-    public void tearDown() {
-        webAdminServer.destroy();
-    }
-
-    public class NormalBehaviour {
-
-        @Before
-        public void setUp() throws Exception {
-            MessageId.Factory messageIdFactory = new DefaultMessageId.Factory();
-            InMemoryMailboxManager mailboxManager = new InMemoryMailboxManager(new InMemoryMailboxSessionMapperFactory(),
-                (userid, passwd) -> true,
-                FakeAuthorizator.defaultReject(),
-                new JVMMailboxPathLocker(),
-                new UnionMailboxACLResolver(),
-                new SimpleGroupMembershipResolver(),
-                new MessageParser(),
-                messageIdFactory);
-            mailboxManager.init();
-
-            createServer(mailboxManager);
-        }
-
-        @Test
-        public void getMailboxesShouldUserErrorFoundWithNonExistingUser() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get()
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void getShouldReturnNotFoundWithNonExistingUser() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnNotFoundWithNonExistingUser() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void deleteShouldReturnNotFoundWithNonExistingUser() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void getShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get(MAILBOX_NAME + "*")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME+ "*")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME + "*")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void getShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get(MAILBOX_NAME + "%")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME+ "%")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteShouldReturnUserErrorWithInvalidPercentMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME + "%")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void getShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get(MAILBOX_NAME + "#")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME+ "#")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteShouldReturnUserErrorWithInvalidSharpMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME + "#")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void getShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .get(MAILBOX_NAME + "&")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME+ "&")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteShouldReturnUserErrorWithInvalidAndMailboxName() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .put(MAILBOX_NAME + "&")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteMailboxesShouldReturnUserErrorWithNonExistingUser() throws Exception {
-            when(usersRepository.contains(USERNAME)).thenReturn(false);
-
-            when()
-                .delete()
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void getMailboxesShouldReturnEmptyListByDefault() {
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void putShouldReturnNotFoundWhenNoMailboxName() {
-            when()
-                .put()
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnNotFoundWhenJustSeparator() {
-            when()
-                .put(SEPARATOR)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnOk() {
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void putShouldReturnOkWhenIssuedTwoTimes() {
-            with()
-                .put(MAILBOX_NAME);
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void putShouldAddAMailbox() {
-            with()
-                .put(MAILBOX_NAME);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[{\"mailboxName\":\"myMailboxName\"}]"));
-        }
-
-        @Test
-        public void getShouldReturnNotFoundWhenMailboxDoesNotExist() {
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void getShouldReturnOkWhenMailboxExists() {
-            with()
-                .put(MAILBOX_NAME);
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldReturnOkWhenMailboxDoesNotExist() {
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldReturnOkWhenMailboxExists() {
-            with()
-                .put(MAILBOX_NAME);
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldRemoveMailbox() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .delete(MAILBOX_NAME);
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void deleteMailboxesShouldReturnOkWhenNoMailboxes() {
-            when()
-                .delete()
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteMailboxesShouldReturnOkWhenMailboxes() {
-            with()
-                .put(MAILBOX_NAME);
-
-            when()
-                .delete()
-                .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteMailboxesShouldRemoveAllUserMailboxes() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put("otherMailbox");
-
-            with()
-                .delete();
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void deleteShouldReturnOkWhenMailboxHasChildren() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put(MAILBOX_NAME + ".child");
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldDeleteAMailboxAndItsChildren() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put(MAILBOX_NAME + ".child");
-
-            with()
-                .delete(MAILBOX_NAME);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void deleteShouldNotDeleteUnrelatedMailbox() {
-            String mailboxName = MAILBOX_NAME + "!child";
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put(mailboxName);
-
-            with()
-                .delete(MAILBOX_NAME);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[{\"mailboxName\":\"" + mailboxName + "\"}]"));
-        }
-
-        @Test
-        public void deleteShouldReturnOkWhenDeletingChildMailboxes() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put(MAILBOX_NAME + ".child");
-
-            when()
-                .delete(MAILBOX_NAME + ".child")
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldBeAbleToRemoveChildMailboxes() {
-            with()
-                .put(MAILBOX_NAME);
-
-            with()
-                .put(MAILBOX_NAME + ".child");
-
-            with()
-                .delete(MAILBOX_NAME + ".child");
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[{\"mailboxName\":\"myMailboxName\"}]"));
-        }
-    }
-
-    public class ExceptionHandling {
-
-        private MailboxManager mailboxManager;
-
-        @Before
-        public void setUp() throws Exception {
-            mailboxManager = mock(MailboxManager.class);
-            when(mailboxManager.createSystemSession(any(), any())).thenReturn(mock(MailboxSession.class));
-
-            createServer(mailboxManager);
-        }
-
-        @Test
-        public void putShouldGenerateInternalErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(mailboxManager).createMailbox(any(), any());
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void putShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
-            doThrow(new MailboxException()).when(mailboxManager).createMailbox(any(), any());
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void putShouldReturnOkOnMailboxExists() throws Exception {
-            doThrow(new MailboxExistsException(MAILBOX_NAME)).when(mailboxManager).createMailbox(any(), any());
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownExceptionOnDelete() throws Exception {
-            MailboxId mailboxId = InMemoryId.of(12);
-            when(mailboxManager.search(any(MailboxQuery.class), any()))
-                .thenReturn(
-                        ImmutableList.of(
-                                new SimpleMailboxMetaData(
-                                        new MailboxPath("#private", USERNAME, MAILBOX_NAME), mailboxId, '.')));
-            doThrow(new RuntimeException()).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownExceptionOnSearch() throws Exception {
-            when(mailboxManager.search(any(MailboxQuery.class), any())).thenThrow(new RuntimeException());
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownMailboxExceptionOnDelete() throws Exception {
-            MailboxId mailboxId = InMemoryId.of(12);
-            when(mailboxManager.search(any(MailboxQuery.class), any()))
-                .thenReturn(
-                        ImmutableList.of(
-                                new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, MAILBOX_NAME), mailboxId, '.')));
-            doThrow(new MailboxException()).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownMailboxExceptionOnSearch() throws Exception {
-            when(mailboxManager.search(any(MailboxQuery.class), any())).thenThrow(new MailboxException());
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldReturnOkOnMailboxDoesNotExists() throws Exception {
-            doThrow(new MailboxNotFoundException(MAILBOX_NAME)).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownExceptionWhenListingMailboxes() throws Exception {
-            doThrow(new RuntimeException()).when(mailboxManager).search(any(MailboxQuery.class), any());
-
-            when()
-                .delete()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnMailboxExceptionWhenListingMailboxes() throws Exception {
-            doThrow(new MailboxException()).when(mailboxManager).search(any(MailboxQuery.class), any());
-
-            when()
-                .delete()
-                .then()
-                .statusCode(500);
-        }
-
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnUnknownExceptionWhenRemovingMailboxes() throws Exception {
-            MailboxId mailboxId = InMemoryId.of(12);
-            when(mailboxManager.search(any(MailboxQuery.class), any()))
-                .thenReturn(
-                        ImmutableList.of(
-                                new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
-            doThrow(new RuntimeException()).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldReturnOkOnMailboxNotFoundExceptionWhenRemovingMailboxes() throws Exception {
-            MailboxId mailboxId = InMemoryId.of(12);
-            when(mailboxManager.search(any(MailboxQuery.class), any()))
-                .thenReturn(
-                        ImmutableList.of(new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
-            doThrow(new MailboxNotFoundException("any")).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete()
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldReturnInternalErrorOnMailboxExceptionWhenRemovingMailboxes() throws Exception {
-            MailboxId mailboxId = InMemoryId.of(12);
-            when(mailboxManager.search(any(MailboxQuery.class), any()))
-                .thenReturn(
-                        ImmutableList.of(new SimpleMailboxMetaData(new MailboxPath("#private", USERNAME, "any"), mailboxId, '.')));
-            doThrow(new MailboxException()).when(mailboxManager).deleteMailbox(any(), any());
-
-            when()
-                .delete()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getShouldGenerateInternalErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(mailboxManager).mailboxExists(any(), any());
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
-            doThrow(new MailboxException()).when(mailboxManager).mailboxExists(any(), any());
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getMailboxesShouldGenerateInternalErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(mailboxManager).search(any(MailboxQuery.class), any());
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getMailboxesShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
-            doThrow(new MailboxException()).when(mailboxManager).search(any(MailboxQuery.class), any());
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getMailboxesShouldGenerateInternalErrorOnRepositoryException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getShouldGenerateInternalErrorOnRepositoryException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
-
-            when()
-                .get(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void putShouldGenerateInternalErrorOnRepositoryException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
-
-            when()
-                .put(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteShouldGenerateInternalErrorOnRepositoryException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
-
-            when()
-                .delete(MAILBOX_NAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void deleteMailboxesShouldGenerateInternalErrorOnRepositoryException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).contains(USERNAME);
-
-            when()
-                .delete()
-                .then()
-                .statusCode(500);
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
deleted file mode 100644
index 684ea9b..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
+++ /dev/null
@@ -1,422 +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.webadmin.routes;
-
-import static com.jayway.restassured.RestAssured.given;
-import static com.jayway.restassured.RestAssured.when;
-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.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.metrics.logger.DefaultMetricFactory;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.api.UsersRepositoryException;
-import org.apache.james.user.api.model.User;
-import org.apache.james.user.memory.MemoryUsersRepository;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.service.UserService;
-import org.apache.james.webadmin.utils.JsonTransformer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.google.common.base.Charsets;
-import com.jayway.restassured.RestAssured;
-import com.jayway.restassured.builder.RequestSpecBuilder;
-import com.jayway.restassured.http.ContentType;
-
-import de.bechte.junit.runners.context.HierarchicalContextRunner;
-
-@RunWith(HierarchicalContextRunner.class)
-public class UsersRoutesTest {
-
-    public static final String DOMAIN = "domain";
-    public static final String USERNAME = "username@" + DOMAIN;
-    private WebAdminServer webAdminServer;
-
-    private void createServer(UsersRepository usersRepository) throws Exception {
-        webAdminServer = new WebAdminServer(
-            new DefaultMetricFactory(),
-            new UserRoutes(new UserService(usersRepository), new JsonTransformer()));
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = new RequestSpecBuilder()
-        		.setContentType(ContentType.JSON)
-        		.setAccept(ContentType.JSON)
-        		.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
-        		.setPort(webAdminServer.getPort().toInt())
-        		.setBasePath(UserRoutes.USERS)
-        		.build();
-    }
-
-    @After
-    public void stop() {
-        webAdminServer.destroy();
-    }
-
-    public class NormalBehaviour {
-
-        @Before
-        public void setUp() throws Exception {
-            DomainList domainList = mock(DomainList.class);
-            when(domainList.containsDomain(DOMAIN)).thenReturn(true);
-
-            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
-            usersRepository.setDomainList(domainList);
-
-            createServer(usersRepository);
-        }
-
-        @Test
-        public void getUsersShouldBeEmptyByDefault() {
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(is("[]"));
-        }
-
-        @Test
-        public void putShouldReturnUserErrorWhenNoBody() {
-            when()
-                .put(USERNAME)
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void postShouldReturnUserErrorWhenEmptyJsonBody() {
-            given()
-                .body("{}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void postShouldReturnUserErrorWhenWrongJsonBody() {
-            given()
-                .body("{\"bad\":\"any\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void postShouldReturnOkWhenValidJsonBody() {
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void postShouldReturnRequireNonNullPassword() {
-            given()
-                .body("{\"password\":null}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void postShouldAddTheUser() {
-            with()
-                .body("{\"password\":\"password\"}")
-            .put(USERNAME);
-
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(equalTo("[{\"username\":\"" + USERNAME + "\"}]"));
-        }
-
-        @Test
-        public void postingTwoTimesShouldBeAllowed() {
-            // Given
-            with()
-                .body("{\"password\":\"password\"}")
-            .put(USERNAME);
-
-            // When
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(204);
-
-            // Then
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(equalTo("[{\"username\":\"" + USERNAME + "\"}]"));
-        }
-
-        @Test
-        public void deleteShouldReturnOk() {
-            when()
-                .delete(USERNAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void deleteShouldReturnBadRequestWhenEmptyUserName() {
-            when()
-                .delete("/")
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void deleteShouldReturnBadRequestWhenUsernameIsTooLong() {
-            when()
-                .delete(USERNAME + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void deleteShouldReturnNotFoundWhenUsernameContainsSlash() {
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME + "/" + USERNAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnBadRequestWhenEmptyUserName() {
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put("/")
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void putShouldReturnBadRequestWhenUsernameIsTooLong() {
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
-                    "0123456789.0123456789.0123456789.")
-            .then()
-                .statusCode(400);
-        }
-
-        @Test
-        public void putShouldReturnNotFoundWhenUsernameContainsSlash() {
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME + "/" + USERNAME)
-            .then()
-                .statusCode(404);
-        }
-
-        @Test
-        public void deleteShouldRemoveAssociatedUser() {
-            // Given
-            with()
-                .body("{\"password\":\"password\"}")
-            .put(USERNAME);
-
-            // When
-            when()
-                .delete(USERNAME)
-            .then()
-                .statusCode(204);
-
-            // Then
-            when()
-                .get()
-            .then()
-                .statusCode(200)
-                .body(equalTo("[]"));
-        }
-
-        @Test
-        public void deleteShouldStillBeValidWithExtraBody() {
-            given()
-                .body("{\"bad\":\"any\"}")
-            .when()
-                .delete(USERNAME)
-            .then()
-                .statusCode(204);
-        }
-    }
-
-    public class ErrorHandling {
-
-        private UsersRepository usersRepository;
-        private String username;
-        private String password;
-
-        @Before
-        public void setUp() throws Exception {
-            usersRepository = mock(UsersRepository.class);
-            createServer(usersRepository);
-            username = "username@domain";
-            password = "password";
-        }
-
-        @Test
-        public void deleteShouldStillBeOkWhenNoUser() throws Exception {
-            doThrow(new UsersRepositoryException("message")).when(usersRepository).removeUser(username);
-
-            when()
-                .delete(USERNAME)
-            .then()
-                .statusCode(204);
-        }
-
-        @Test
-        public void getShouldFailOnRepositoryException() throws Exception {
-            when(usersRepository.list()).thenThrow(new UsersRepositoryException("message"));
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void postShouldFailOnRepositoryExceptionOnGetUserByName() throws Exception {
-            when(usersRepository.getUserByName(username)).thenThrow(new UsersRepositoryException("message"));
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void postShouldNotFailOnRepositoryExceptionOnAddUser() throws Exception {
-            when(usersRepository.getUserByName(username)).thenReturn(null);
-            doThrow(new UsersRepositoryException("message")).when(usersRepository).addUser(username, password);
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(409);
-        }
-
-        @Test
-        public void postShouldFailOnRepositoryExceptionOnUpdateUser() throws Exception {
-            when(usersRepository.getUserByName(username)).thenReturn(mock(User.class));
-            doThrow(new UsersRepositoryException("message")).when(usersRepository).updateUser(any());
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(409);
-        }
-
-
-        @Test
-        public void deleteShouldFailOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(usersRepository).removeUser(username);
-
-            when()
-                .delete(USERNAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void getShouldFailOnUnknownException() throws Exception {
-            when(usersRepository.list()).thenThrow(new RuntimeException());
-
-            when()
-                .get()
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void postShouldFailOnUnknownExceptionOnGetUserByName() throws Exception {
-            when(usersRepository.getUserByName(username)).thenThrow(new RuntimeException());
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void postShouldFailOnUnknownExceptionOnAddUser() throws Exception {
-            when(usersRepository.getUserByName(username)).thenReturn(null);
-            doThrow(new RuntimeException()).when(usersRepository).addUser(username, password);
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(500);
-        }
-
-        @Test
-        public void postShouldFailOnUnknownExceptionOnGetUpdateUser() throws Exception {
-            when(usersRepository.getUserByName(username)).thenReturn(mock(User.class));
-            doThrow(new RuntimeException()).when(usersRepository).updateUser(any());
-
-            given()
-                .body("{\"password\":\"password\"}")
-            .when()
-                .put(USERNAME)
-            .then()
-                .statusCode(500);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
deleted file mode 100644
index ff5f2cb..0000000
--- a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
+++ /dev/null
@@ -1,114 +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.webadmin.utils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-
-public class JsonExtractorTest {
-
-    private JsonExtractor<Request> jsonExtractor;
-
-    @Before
-    public void setUp() {
-        jsonExtractor = new JsonExtractor<>(Request.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnNullInput() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse(null)).isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnEmptyInput() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnBrokenJson() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"broken")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnEmptyJson() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{}")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnMissingMandatoryField() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"any\"}")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnValidationProblemIllegalArgumentException() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"\",\"field2\":\"any\"}")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnValidationProblemNPE() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":null,\"field2\":\"any\"}")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldThrowOnExtraFiled() throws Exception {
-        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"value\",\"field2\":\"any\",\"extra\":\"extra\"}")).isInstanceOf(JsonExtractException.class);
-    }
-
-    @Test
-    public void parseShouldInstantiateDestinationClass() throws Exception {
-        String field1 = "value1";
-        String field2 = "value2";
-        Request request = jsonExtractor.parse("{\"field1\":\"" + field1 + "\",\"field2\":\"" + field2 + "\"}");
-
-        assertThat(request.getField1()).isEqualTo(field1);
-        assertThat(request.getField2()).isEqualTo(field2);
-    }
-
-    static class Request {
-        private final String field1;
-        private final String field2;
-
-        @JsonCreator
-        public Request(@JsonProperty("field1") String field1,
-                       @JsonProperty("field2") String field2) {
-            Preconditions.checkNotNull(field1);
-            Preconditions.checkNotNull(field2);
-            Preconditions.checkArgument(!field1.isEmpty());
-            this.field1 = field1;
-            this.field2 = field2;
-        }
-
-        public String getField1() {
-            return field1;
-        }
-
-        public String getField2() {
-            return field2;
-        }
-    }
-
-}


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


[2/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
new file mode 100644
index 0000000..ff5f2cb
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/JsonExtractorTest.java
@@ -0,0 +1,114 @@
+/****************************************************************
+ * 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.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+
+public class JsonExtractorTest {
+
+    private JsonExtractor<Request> jsonExtractor;
+
+    @Before
+    public void setUp() {
+        jsonExtractor = new JsonExtractor<>(Request.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnNullInput() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse(null)).isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnEmptyInput() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnBrokenJson() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"broken")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnEmptyJson() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{}")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnMissingMandatoryField() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"any\"}")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnValidationProblemIllegalArgumentException() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"\",\"field2\":\"any\"}")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnValidationProblemNPE() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":null,\"field2\":\"any\"}")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldThrowOnExtraFiled() throws Exception {
+        assertThatThrownBy(() -> jsonExtractor.parse("{\"field1\":\"value\",\"field2\":\"any\",\"extra\":\"extra\"}")).isInstanceOf(JsonExtractException.class);
+    }
+
+    @Test
+    public void parseShouldInstantiateDestinationClass() throws Exception {
+        String field1 = "value1";
+        String field2 = "value2";
+        Request request = jsonExtractor.parse("{\"field1\":\"" + field1 + "\",\"field2\":\"" + field2 + "\"}");
+
+        assertThat(request.getField1()).isEqualTo(field1);
+        assertThat(request.getField2()).isEqualTo(field2);
+    }
+
+    static class Request {
+        private final String field1;
+        private final String field2;
+
+        @JsonCreator
+        public Request(@JsonProperty("field1") String field1,
+                       @JsonProperty("field2") String field2) {
+            Preconditions.checkNotNull(field1);
+            Preconditions.checkNotNull(field2);
+            Preconditions.checkArgument(!field1.isEmpty());
+            this.field1 = field1;
+            this.field2 = field2;
+        }
+
+        public String getField1() {
+            return field1;
+        }
+
+        public String getField2() {
+            return field2;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/pom.xml b/server/protocols/webadmin/webadmin-data/pom.xml
new file mode 100644
index 0000000..781baff
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/pom.xml
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>james-server</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta6-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>james-server-webadmin-data</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Apache James :: Server :: Web Admin :: data</name>
+
+    <profiles>
+        <profile>
+            <id>noTest</id>
+            <activation>
+                <os>
+                    <family>windows</family>
+                </os>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-util-java8</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-data-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-data-memory</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-core</artifactId>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>metrics-logger</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.jayway.restassured</groupId>
+                    <artifactId>rest-assured</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>de.bechte.junit</groupId>
+                    <artifactId>junit-hierarchicalcontextrunner</artifactId>
+                    <version>4.11.3</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>javax.inject</groupId>
+                    <artifactId>javax.inject</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.assertj</groupId>
+                    <artifactId>assertj-core</artifactId>
+                    <version>${assertj-3.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.mockito</groupId>
+                    <artifactId>mockito-core</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.hamcrest</groupId>
+                    <artifactId>java-hamcrest</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <configuration>
+                            <archive>
+                                <manifest>
+                                    <mainClass>fully.qualified.MainClass</mainClass>
+                                </manifest>
+                            </archive>
+                            <descriptorRefs>
+                                <descriptorRef>jar-with-dependencies</descriptorRef>
+                            </descriptorRefs>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
new file mode 100644
index 0000000..1d102c2
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/AddUserRequest.java
@@ -0,0 +1,39 @@
+/****************************************************************
+ * 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 com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+
+public class AddUserRequest {
+
+    private final char[] password;
+
+    @JsonCreator
+    public AddUserRequest(@JsonProperty("password") char[] password) {
+        Preconditions.checkNotNull(password);
+        this.password = password;
+    }
+
+    public char[] getPassword() {
+        return password;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/UserResponse.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
new file mode 100644
index 0000000..5fe1846
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/dto/UserResponse.java
@@ -0,0 +1,33 @@
+/****************************************************************
+ * 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;
+
+public class UserResponse {
+
+    private final String username;
+
+    public UserResponse(String username) {
+        this.username = username;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
new file mode 100644
index 0000000..2008278
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
@@ -0,0 +1,118 @@
+/****************************************************************
+ * 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.routes;
+
+import static org.apache.james.webadmin.Constants.SEPARATOR;
+
+import javax.inject.Inject;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.webadmin.Constants;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import spark.Request;
+import spark.Response;
+import spark.Service;
+
+public class DomainRoutes implements Routes {
+
+    private static final String DOMAIN_NAME = ":domainName";
+    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutes.class);
+
+    public static final String DOMAINS = "/domains";
+    public static final String SPECIFIC_DOMAIN = DOMAINS + SEPARATOR + DOMAIN_NAME;
+    public static final int MAXIMUM_DOMAIN_SIZE = 256;
+
+
+    private final DomainList domainList;
+    private final JsonTransformer jsonTransformer;
+
+    @Inject
+    public DomainRoutes(DomainList domainList, JsonTransformer jsonTransformer) {
+        this.domainList = domainList;
+        this.jsonTransformer = jsonTransformer;
+    }
+
+    @Override
+    public void define(Service service) {
+        service.get(DOMAINS,
+            (request, response) -> domainList.getDomains(),
+            jsonTransformer);
+
+        service.get(SPECIFIC_DOMAIN, this::exists);
+
+        service.put(SPECIFIC_DOMAIN, this::addDomain);
+
+        service.delete(SPECIFIC_DOMAIN, this::removeDomain);
+    }
+
+    private String removeDomain(Request request, Response response) {
+        try {
+            String domain = request.params(DOMAIN_NAME);
+            removeDomain(domain);
+        } catch (DomainListException e) {
+            LOGGER.info("{} did not exists", request.params(DOMAIN_NAME));
+        }
+        response.status(204);
+        return Constants.EMPTY_BODY;
+    }
+
+    private void removeDomain(String domain) throws DomainListException {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
+        domainList.removeDomain(domain);
+    }
+
+    private String addDomain(Request request, Response response) {
+        try {
+            addDomain(request.params(DOMAIN_NAME));
+            response.status(204);
+        } catch (DomainListException e) {
+            LOGGER.info("{} already exists", request.params(DOMAIN_NAME));
+            response.status(204);
+        } catch (IllegalArgumentException e) {
+            LOGGER.info("Invalid request for domain creation");
+            response.status(400);
+        }
+        return Constants.EMPTY_BODY;
+    }
+
+    private void addDomain(String domain) throws DomainListException {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
+        Preconditions.checkArgument(!domain.contains("@"));
+        Preconditions.checkArgument(domain.length() < MAXIMUM_DOMAIN_SIZE);
+        domainList.addDomain(domain);
+    }
+
+    private String exists(Request request, Response response) throws DomainListException {
+        if (!domainList.containsDomain(request.params(DOMAIN_NAME))) {
+            response.status(404);
+        } else {
+            response.status(204);
+        }
+        return Constants.EMPTY_BODY;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
new file mode 100644
index 0000000..0ead90a
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
@@ -0,0 +1,104 @@
+/****************************************************************
+ * 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.routes;
+
+import static org.apache.james.webadmin.Constants.SEPARATOR;
+
+import javax.inject.Inject;
+
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.webadmin.Constants;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.AddUserRequest;
+import org.apache.james.webadmin.service.UserService;
+import org.apache.james.webadmin.utils.JsonExtractException;
+import org.apache.james.webadmin.utils.JsonExtractor;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import spark.Request;
+import spark.Response;
+import spark.Service;
+
+public class UserRoutes implements Routes {
+
+    private static final String USER_NAME = ":userName";
+    private static final Logger LOGGER = LoggerFactory.getLogger(UserRoutes.class);
+
+    public static final String USERS = "/users";
+
+    private final UserService userService;
+    private final JsonTransformer jsonTransformer;
+    private final JsonExtractor<AddUserRequest> jsonExtractor;
+
+    @Inject
+    public UserRoutes(UserService userService, JsonTransformer jsonTransformer) {
+        this.userService = userService;
+        this.jsonTransformer = jsonTransformer;
+        this.jsonExtractor = new JsonExtractor<>(AddUserRequest.class);
+    }
+
+    @Override
+    public void define(Service service) {
+        service.get(USERS,
+            (request, response) -> userService.getUsers(),
+            jsonTransformer);
+
+        service.put(USERS + SEPARATOR + USER_NAME, this::upsertUser);
+
+        service.delete(USERS + SEPARATOR + USER_NAME, this::removeUser);
+    }
+
+    private String removeUser(Request request, Response response) {
+        String username = request.params(USER_NAME);
+        try {
+            userService.removeUser(username);
+            response.status(204);
+            return Constants.EMPTY_BODY;
+        } catch (UsersRepositoryException e) {
+            response.status(204);
+            return "The user " + username + " does not exists";
+        } catch (IllegalArgumentException e) {
+            LOGGER.info("Invalid user path", e);
+            response.status(400);
+            return Constants.EMPTY_BODY;
+        }
+    }
+
+    private String upsertUser(Request request, Response response) throws UsersRepositoryException {
+        try {
+            return userService.upsertUser(request.params(USER_NAME),
+                jsonExtractor.parse(request.body()).getPassword(),
+                response);
+        } catch (JsonExtractException e) {
+            LOGGER.info("Error while deserializing addUser request", e);
+            response.status(400);
+            return Constants.EMPTY_BODY;
+        } catch (IllegalArgumentException e) {
+            LOGGER.info("Invalid user path", e);
+            response.status(400);
+            return Constants.EMPTY_BODY;
+        }
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
new file mode 100644
index 0000000..ee0952d
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * 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.service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.user.api.model.User;
+import org.apache.james.util.streams.Iterators;
+import org.apache.james.webadmin.dto.UserResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import spark.Response;
+
+public class UserService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
+    private static final String EMPTY_BODY = "";
+    public static final int MAXIMUM_MAIL_ADDRESS_LENGTH = 255;
+
+    private final UsersRepository usersRepository;
+
+    @Inject
+    public UserService(UsersRepository usersRepository) {
+        this.usersRepository = usersRepository;
+    }
+
+    public List<UserResponse> getUsers() throws UsersRepositoryException {
+        return  Optional.ofNullable(usersRepository.list())
+            .map(Iterators::toStream)
+            .orElse(Stream.of())
+            .map(UserResponse::new)
+            .collect(Guavate.toImmutableList());
+    }
+
+    public void removeUser(String username) throws UsersRepositoryException {
+        usernamePreconditions(username);
+        usersRepository.removeUser(username);
+    }
+
+    public String upsertUser(String username, char[] password, Response response) throws UsersRepositoryException {
+        usernamePreconditions(username);
+        User user = usersRepository.getUserByName(username);
+        try {
+            upsert(user, username, password);
+            response.status(204);
+        } catch (UsersRepositoryException e) {
+            LOGGER.info("Error creating or updating user : {}", e.getMessage());
+            response.status(409);
+        }
+        return EMPTY_BODY;
+    }
+
+    private void usernamePreconditions(String username) {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(username));
+        Preconditions.checkArgument(username.length() < MAXIMUM_MAIL_ADDRESS_LENGTH);
+    }
+
+    private void upsert(User user, String username, char[] password) throws UsersRepositoryException {
+        if (user == null) {
+            usersRepository.addUser(username, new String(password));
+        } else {
+            user.setPassword(new String(password));
+            usersRepository.updateUser(user);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
new file mode 100644
index 0000000..1df89d2
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
@@ -0,0 +1,326 @@
+/****************************************************************
+ * 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.routes;
+
+import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
+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.apache.james.webadmin.Constants.SEPARATOR;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Charsets;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+@RunWith(HierarchicalContextRunner.class)
+public class DomainRoutesTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutesTest.class);
+    public static final String DOMAIN = "domain";
+
+    private WebAdminServer webAdminServer;
+
+    private void createServer(DomainList domainList) throws Exception {
+        webAdminServer = new WebAdminServer(
+            new DefaultMetricFactory(),
+            new DomainRoutes(domainList, new JsonTransformer()));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = new RequestSpecBuilder()
+        		.setContentType(ContentType.JSON)
+        		.setAccept(ContentType.JSON)
+        		.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
+        		.setPort(webAdminServer.getPort().toInt())
+        		.setBasePath(DomainRoutes.DOMAINS)
+        		.build();
+
+    }
+
+    @After
+    public void stop() {
+        webAdminServer.destroy();
+    }
+
+    public class NormalBehaviour {
+
+        @Before
+        public void setUp() throws Exception {
+            DNSService dnsService = mock(DNSService.class);
+            when(dnsService.getHostName(any())).thenReturn("localhost");
+            when(dnsService.getLocalHost()).thenReturn(InetAddress.getByName("localhost"));
+
+            MemoryDomainList domainList = new MemoryDomainList();
+            domainList.setDNSService(dnsService);
+            domainList.setLog(LOGGER);
+            domainList.setAutoDetectIP(false);
+            createServer(domainList);
+        }
+
+        @Test
+        public void getDomainsShouldBeEmptyByDefault() {
+            given()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void putShouldReturnErrorWhenUsedWithEmptyDomain() {
+            given()
+                .put(SEPARATOR)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteShouldReturnErrorWhenUsedWithEmptyDomain() {
+            given()
+                .delete(SEPARATOR)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldBeOk() {
+            given()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainsShouldDisplayAddedDomains() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(containsString(DOMAIN));
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameContainsAT() {
+            when()
+                .put(DOMAIN + "@" + DOMAIN)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameContainsUrlSeparator() {
+            when()
+                .put(DOMAIN + "/" + DOMAIN)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameIsTooLong() {
+            when()
+                .put(DOMAIN + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldWorkOnTheSecondTimeForAGivenValue() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldRemoveTheGivenDomain() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void deleteShouldBeOkWhenTheDomainIsNotPresent() {
+            given()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnOkWhenTheDomainIsPresent() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnNotFoundWhenTheDomainIsAbsent() {
+            given()
+                .get(DOMAIN)
+            .then()
+                .statusCode(404);
+        }
+
+    }
+
+    public class ExceptionHandling {
+
+        private DomainList domainList;
+        private String domain;
+
+        @Before
+        public void setUp() throws Exception {
+            domainList = mock(DomainList.class);
+            createServer(domainList);
+            domain = "domain";
+        }
+
+        @Test
+        public void deleteShouldReturnErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(domainList).removeDomain(domain);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void putShouldReturnErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(domainList).addDomain(domain);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainShouldReturnErrorOnUnknownException() throws Exception {
+            when(domainList.containsDomain(domain)).thenThrow(new RuntimeException());
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainsShouldReturnErrorOnUnknownException() throws Exception {
+            when(domainList.getDomains()).thenThrow(new RuntimeException());
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenDomainListException() throws Exception {
+            doThrow(new DomainListException("message")).when(domainList).removeDomain(domain);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void putShouldReturnOkWhenDomainListException() throws Exception {
+            doThrow(new DomainListException("message")).when(domainList).addDomain(domain);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnErrorOnDomainListException() throws Exception {
+            when(domainList.containsDomain(domain)).thenThrow(new DomainListException("message"));
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainsShouldReturnErrorOnDomainListException() throws Exception {
+            when(domainList.getDomains()).thenThrow(new DomainListException("message"));
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
new file mode 100644
index 0000000..684ea9b
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsersRoutesTest.java
@@ -0,0 +1,422 @@
+/****************************************************************
+ * 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.routes;
+
+import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
+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.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.user.api.model.User;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.service.UserService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.google.common.base.Charsets;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+@RunWith(HierarchicalContextRunner.class)
+public class UsersRoutesTest {
+
+    public static final String DOMAIN = "domain";
+    public static final String USERNAME = "username@" + DOMAIN;
+    private WebAdminServer webAdminServer;
+
+    private void createServer(UsersRepository usersRepository) throws Exception {
+        webAdminServer = new WebAdminServer(
+            new DefaultMetricFactory(),
+            new UserRoutes(new UserService(usersRepository), new JsonTransformer()));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = new RequestSpecBuilder()
+        		.setContentType(ContentType.JSON)
+        		.setAccept(ContentType.JSON)
+        		.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
+        		.setPort(webAdminServer.getPort().toInt())
+        		.setBasePath(UserRoutes.USERS)
+        		.build();
+    }
+
+    @After
+    public void stop() {
+        webAdminServer.destroy();
+    }
+
+    public class NormalBehaviour {
+
+        @Before
+        public void setUp() throws Exception {
+            DomainList domainList = mock(DomainList.class);
+            when(domainList.containsDomain(DOMAIN)).thenReturn(true);
+
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
+            usersRepository.setDomainList(domainList);
+
+            createServer(usersRepository);
+        }
+
+        @Test
+        public void getUsersShouldBeEmptyByDefault() {
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNoBody() {
+            when()
+                .put(USERNAME)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void postShouldReturnUserErrorWhenEmptyJsonBody() {
+            given()
+                .body("{}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void postShouldReturnUserErrorWhenWrongJsonBody() {
+            given()
+                .body("{\"bad\":\"any\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void postShouldReturnOkWhenValidJsonBody() {
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void postShouldReturnRequireNonNullPassword() {
+            given()
+                .body("{\"password\":null}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void postShouldAddTheUser() {
+            with()
+                .body("{\"password\":\"password\"}")
+            .put(USERNAME);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(equalTo("[{\"username\":\"" + USERNAME + "\"}]"));
+        }
+
+        @Test
+        public void postingTwoTimesShouldBeAllowed() {
+            // Given
+            with()
+                .body("{\"password\":\"password\"}")
+            .put(USERNAME);
+
+            // When
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(204);
+
+            // Then
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(equalTo("[{\"username\":\"" + USERNAME + "\"}]"));
+        }
+
+        @Test
+        public void deleteShouldReturnOk() {
+            when()
+                .delete(USERNAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldReturnBadRequestWhenEmptyUserName() {
+            when()
+                .delete("/")
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteShouldReturnBadRequestWhenUsernameIsTooLong() {
+            when()
+                .delete(USERNAME + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void deleteShouldReturnNotFoundWhenUsernameContainsSlash() {
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME + "/" + USERNAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnBadRequestWhenEmptyUserName() {
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put("/")
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnBadRequestWhenUsernameIsTooLong() {
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789." +
+                    "0123456789.0123456789.0123456789.")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnNotFoundWhenUsernameContainsSlash() {
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME + "/" + USERNAME)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteShouldRemoveAssociatedUser() {
+            // Given
+            with()
+                .body("{\"password\":\"password\"}")
+            .put(USERNAME);
+
+            // When
+            when()
+                .delete(USERNAME)
+            .then()
+                .statusCode(204);
+
+            // Then
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(equalTo("[]"));
+        }
+
+        @Test
+        public void deleteShouldStillBeValidWithExtraBody() {
+            given()
+                .body("{\"bad\":\"any\"}")
+            .when()
+                .delete(USERNAME)
+            .then()
+                .statusCode(204);
+        }
+    }
+
+    public class ErrorHandling {
+
+        private UsersRepository usersRepository;
+        private String username;
+        private String password;
+
+        @Before
+        public void setUp() throws Exception {
+            usersRepository = mock(UsersRepository.class);
+            createServer(usersRepository);
+            username = "username@domain";
+            password = "password";
+        }
+
+        @Test
+        public void deleteShouldStillBeOkWhenNoUser() throws Exception {
+            doThrow(new UsersRepositoryException("message")).when(usersRepository).removeUser(username);
+
+            when()
+                .delete(USERNAME)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getShouldFailOnRepositoryException() throws Exception {
+            when(usersRepository.list()).thenThrow(new UsersRepositoryException("message"));
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void postShouldFailOnRepositoryExceptionOnGetUserByName() throws Exception {
+            when(usersRepository.getUserByName(username)).thenThrow(new UsersRepositoryException("message"));
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void postShouldNotFailOnRepositoryExceptionOnAddUser() throws Exception {
+            when(usersRepository.getUserByName(username)).thenReturn(null);
+            doThrow(new UsersRepositoryException("message")).when(usersRepository).addUser(username, password);
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(409);
+        }
+
+        @Test
+        public void postShouldFailOnRepositoryExceptionOnUpdateUser() throws Exception {
+            when(usersRepository.getUserByName(username)).thenReturn(mock(User.class));
+            doThrow(new UsersRepositoryException("message")).when(usersRepository).updateUser(any());
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(409);
+        }
+
+
+        @Test
+        public void deleteShouldFailOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(usersRepository).removeUser(username);
+
+            when()
+                .delete(USERNAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getShouldFailOnUnknownException() throws Exception {
+            when(usersRepository.list()).thenThrow(new RuntimeException());
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void postShouldFailOnUnknownExceptionOnGetUserByName() throws Exception {
+            when(usersRepository.getUserByName(username)).thenThrow(new RuntimeException());
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void postShouldFailOnUnknownExceptionOnAddUser() throws Exception {
+            when(usersRepository.getUserByName(username)).thenReturn(null);
+            doThrow(new RuntimeException()).when(usersRepository).addUser(username, password);
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void postShouldFailOnUnknownExceptionOnGetUpdateUser() throws Exception {
+            when(usersRepository.getUserByName(username)).thenReturn(mock(User.class));
+            doThrow(new RuntimeException()).when(usersRepository).updateUser(any());
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME)
+            .then()
+                .statusCode(500);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
new file mode 100644
index 0000000..3b17b61
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>james-server</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta6-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>james-server-webadmin-mailbox</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Apache James :: Server :: Web Admin :: mailbox</name>
+
+    <profiles>
+        <profile>
+            <id>noTest</id>
+            <activation>
+                <os>
+                    <family>windows</family>
+                </os>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>apache-james-mailbox-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>apache-james-mailbox-memory</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-util-java8</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-data-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-data-memory</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>metrics-logger</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.jayway.restassured</groupId>
+                    <artifactId>rest-assured</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>de.bechte.junit</groupId>
+                    <artifactId>junit-hierarchicalcontextrunner</artifactId>
+                    <version>4.11.3</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>javax.inject</groupId>
+                    <artifactId>javax.inject</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.assertj</groupId>
+                    <artifactId>assertj-core</artifactId>
+                    <version>${assertj-3.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.mockito</groupId>
+                    <artifactId>mockito-core</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.hamcrest</groupId>
+                    <artifactId>java-hamcrest</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <configuration>
+                            <archive>
+                                <manifest>
+                                    <mainClass>fully.qualified.MainClass</mainClass>
+                                </manifest>
+                            </archive>
+                            <descriptorRefs>
+                                <descriptorRef>jar-with-dependencies</descriptorRef>
+                            </descriptorRefs>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
new file mode 100644
index 0000000..b552f45
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/MailboxResponse.java
@@ -0,0 +1,33 @@
+/****************************************************************
+ * 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;
+
+public class MailboxResponse {
+
+    private final String mailboxName;
+
+    public MailboxResponse(String mailboxName) {
+        this.mailboxName = mailboxName;
+    }
+
+    public String getMailboxName() {
+        return mailboxName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
new file mode 100644
index 0000000..b3403ae
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * 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.model.Quota;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.common.base.Preconditions;
+
+@JsonDeserialize(builder = QuotaDTO.Builder.class)
+public class QuotaDTO {
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    @JsonPOJOBuilder(withPrefix="")
+    public static class Builder {
+        private long count;
+        private long size;
+
+        public Builder count(long count) {
+            this.count = count;
+            return this;
+        }
+
+        public Builder size(long size) {
+            this.size = size;
+            return this;
+        }
+
+        public QuotaDTO build() {
+            return new QuotaDTO(count, size);
+        }
+
+    }
+
+    private final long count;
+    private final long size;
+
+    private QuotaDTO(long count, long size) {
+        Preconditions.checkArgument(count >= Quota.UNLIMITED);
+        Preconditions.checkArgument(size >= Quota.UNLIMITED);
+        this.count = count;
+        this.size = size;
+    }
+
+    public long getCount() {
+        return count;
+    }
+
+    public long getSize() {
+        return size;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
new file mode 100644
index 0000000..7ae9e85
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaRequest.java
@@ -0,0 +1,39 @@
+/****************************************************************
+ * 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 com.google.common.base.Preconditions;
+
+public class QuotaRequest {
+    public static QuotaRequest parse(String serialized) {
+        return new QuotaRequest(Long.valueOf(serialized));
+    }
+
+    private final long value;
+
+    public QuotaRequest(long value) {
+        Preconditions.checkArgument(value >= 0);
+        this.value = value;
+    }
+
+    public long getValue() {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
new file mode 100644
index 0000000..eeca83a
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
@@ -0,0 +1,130 @@
+/****************************************************************
+ * 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.routes;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
+import org.apache.james.webadmin.Constants;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.QuotaRequest;
+import org.apache.james.webadmin.utils.JsonExtractException;
+import org.apache.james.webadmin.utils.JsonExtractor;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import spark.Service;
+
+public class GlobalQuotaRoutes implements Routes {
+
+    public static final String QUOTA_ENDPOINT = "/quota";
+    public static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
+    public static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
+    private static final Logger LOGGER = LoggerFactory.getLogger(Routes.class);
+
+    private final MaxQuotaManager maxQuotaManager;
+    private final JsonTransformer jsonTransformer;
+    private final JsonExtractor<QuotaDTO> jsonExtractor;
+
+    @Inject
+    public GlobalQuotaRoutes(MaxQuotaManager maxQuotaManager, JsonTransformer jsonTransformer) {
+        this.maxQuotaManager = maxQuotaManager;
+        this.jsonTransformer = jsonTransformer;
+        this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class);
+    }
+
+    @Override
+    public void define(Service service) {
+        service.get(COUNT_ENDPOINT, (request, response) -> {
+            long value = maxQuotaManager.getDefaultMaxMessage();
+            response.status(200);
+            return value;
+        }, jsonTransformer);
+
+        service.delete(COUNT_ENDPOINT, (request, response) -> {
+            maxQuotaManager.setDefaultMaxMessage(Quota.UNLIMITED);
+            response.status(204);
+            return Constants.EMPTY_BODY;
+        });
+
+        service.put(COUNT_ENDPOINT, (request, response) -> {
+            try {
+                QuotaRequest quotaRequest = QuotaRequest.parse(request.body());
+                maxQuotaManager.setDefaultMaxMessage(quotaRequest.getValue());
+                response.status(204);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Invalid quota. Need to be an integer value greater than 0");
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.get(SIZE_ENDPOINT, (request, response) -> {
+            long value = maxQuotaManager.getDefaultMaxStorage();
+            response.status(200);
+            return value;
+        }, jsonTransformer);
+
+        service.delete(SIZE_ENDPOINT, (request, response) -> {
+            maxQuotaManager.setDefaultMaxStorage(Quota.UNLIMITED);
+            response.status(204);
+            return Constants.EMPTY_BODY;
+        });
+
+        service.put(SIZE_ENDPOINT, (request, response) -> {
+            try {
+                QuotaRequest quotaRequest = QuotaRequest.parse(request.body());
+                maxQuotaManager.setDefaultMaxStorage(quotaRequest.getValue());
+                response.status(204);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Invalid quota. Need to be an integer value greater than 0");
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        });
+
+        service.get(QUOTA_ENDPOINT, (request, response) -> {
+            QuotaDTO quotaDTO = QuotaDTO.builder()
+                .count(maxQuotaManager.getDefaultMaxMessage())
+                .size(maxQuotaManager.getDefaultMaxStorage()).build();
+            response.status(200);
+            return quotaDTO;
+        }, jsonTransformer);
+
+        service.put(QUOTA_ENDPOINT, ((request, response) -> {
+            try {
+                QuotaDTO quotaDTO = jsonExtractor.parse(request.body());
+                maxQuotaManager.setDefaultMaxMessage(quotaDTO.getCount());
+                maxQuotaManager.setDefaultMaxStorage(quotaDTO.getSize());
+                response.status(204);
+            } catch (JsonExtractException e) {
+                LOGGER.info("Malformed JSON", e);
+                response.status(400);
+            } catch (IllegalArgumentException e) {
+                LOGGER.info("Quota should be positive or unlimited (-1)", e);
+                response.status(400);
+            }
+            return Constants.EMPTY_BODY;
+        }));
+    }
+}


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


[7/7] james-project git commit: JAMES-1950 Enable metrics reporting with DNS service

Posted by bt...@apache.org.
JAMES-1950 Enable metrics reporting with DNS service


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

Branch: refs/heads/master
Commit: 5d3bedee1898ea446650a794beaba4e60f7988d5
Parents: cca0f39
Author: benwa <bt...@linagora.com>
Authored: Fri Mar 31 19:41:04 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Mon Apr 3 15:33:38 2017 +0700

----------------------------------------------------------------------
 server/dns-service/dnsservice-dnsjava/pom.xml   |  4 ++
 .../dnsservice/dnsjava/DNSJavaService.java      | 53 +++++++++++++++-----
 .../dnsservice/dnsjava/DNSJavaServiceTest.java  |  6 +++
 3 files changed, 51 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5d3bedee/server/dns-service/dnsservice-dnsjava/pom.xml
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-dnsjava/pom.xml b/server/dns-service/dnsservice-dnsjava/pom.xml
index b15d23e..6a27d3f 100644
--- a/server/dns-service/dnsservice-dnsjava/pom.xml
+++ b/server/dns-service/dnsservice-dnsjava/pom.xml
@@ -42,6 +42,10 @@
             <artifactId>james-server-lifecycle-api</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>metrics-api</artifactId>
+        </dependency>
+        <dependency>
             <groupId>commons-configuration</groupId>
             <artifactId>commons-configuration</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/5d3bedee/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java b/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
index fbb44f0..80b4703 100644
--- a/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
+++ b/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
@@ -25,6 +25,8 @@ import org.apache.james.dnsservice.api.DNSServiceMBean;
 import org.apache.james.dnsservice.api.TemporaryResolutionException;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.lifecycle.api.LogEnabled;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.metrics.api.TimeMetric;
 import org.slf4j.Logger;
 import org.xbill.DNS.ARecord;
 import org.xbill.DNS.Cache;
@@ -44,6 +46,8 @@ import org.xbill.DNS.TextParseException;
 import org.xbill.DNS.Type;
 
 import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
@@ -85,6 +89,8 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
      */
     private final List<String> dnsServers = new ArrayList<String>();
 
+    private final MetricFactory metricFactory;
+
     /**
      * The search paths to be used
      */
@@ -113,6 +119,11 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
         this.logger = logger;
     }
 
+    @Inject
+    public DNSJavaService(MetricFactory metricFactory) {
+        this.metricFactory = metricFactory;
+    }
+
     @Override
     public void configure(HierarchicalConfiguration configuration) throws ConfigurationException {
 
@@ -306,6 +317,7 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
 
     @Override
     public Collection<String> findMXRecords(String hostname) throws TemporaryResolutionException {
+        TimeMetric timeMetric = metricFactory.timer("findMXRecords");
         List<String> servers = new ArrayList<String>();
         try {
             servers = findMXRecordsRaw(hostname);
@@ -327,6 +339,7 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
                     logger.error(logBuffer.toString());
                 }
             }
+            timeMetric.stopAndPublish();
         }
     }
 
@@ -424,6 +437,7 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
 
     @Override
     public InetAddress getByName(String host) throws UnknownHostException {
+        TimeMetric timeMetric = metricFactory.timer("getByName");
         String name = allowIPLiteral(host);
 
         try {
@@ -441,11 +455,14 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
                 return InetAddress.getByAddress(name, a.getAddress().getAddress());
             } else
                 throw e;
+        } finally {
+            timeMetric.stopAndPublish();
         }
     }
 
     @Override
     public InetAddress[] getAllByName(String host) throws UnknownHostException {
+        TimeMetric timeMetric = metricFactory.timer("getAllByName");
         String name = allowIPLiteral(host);
         try {
             // Check if its local
@@ -467,37 +484,49 @@ public class DNSJavaService implements DNSService, DNSServiceMBean, LogEnabled,
                 return addrs;
             } else
                 throw e;
+        } finally {
+            timeMetric.stopAndPublish();
         }
     }
 
     @Override
     public Collection<String> findTXTRecords(String hostname) {
+        TimeMetric timeMetric = metricFactory.timer("findTXTRecords");
         List<String> txtR = new ArrayList<String>();
         Record[] records = lookupNoException(hostname, Type.TXT, "TXT");
 
-        if (records != null) {
-            for (Record record : records) {
-                TXTRecord txt = (TXTRecord) record;
-                txtR.add(txt.rdataToString());
-            }
+        try {
+            if (records != null) {
+                for (Record record : records) {
+                    TXTRecord txt = (TXTRecord) record;
+                    txtR.add(txt.rdataToString());
+                }
 
+            }
+            return txtR;
+        } finally {
+            timeMetric.stopAndPublish();
         }
-        return txtR;
     }
 
     @Override
     public String getHostName(InetAddress addr) {
+        TimeMetric timeMetric = metricFactory.timer("getHostName");
         String result;
         Name name = ReverseMap.fromAddress(addr);
         Record[] records = lookupNoException(name.toString(), Type.PTR, "PTR");
 
-        if (records == null) {
-            result = addr.getHostAddress();
-        } else {
-            PTRRecord ptr = (PTRRecord) records[0];
-            result = ptr.getTarget().toString();
+        try {
+            if (records == null) {
+                result = addr.getHostAddress();
+            } else {
+                PTRRecord ptr = (PTRRecord) records[0];
+                result = ptr.getTarget().toString();
+            }
+            return result;
+        } finally {
+            timeMetric.stopAndPublish();
         }
-        return result;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/5d3bedee/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java b/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
index 7c6842d..70eb870 100644
--- a/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
+++ b/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
@@ -20,6 +20,8 @@ package org.apache.james.dnsservice.dnsjava;
 
 import com.google.common.io.Resources;
 import org.apache.commons.configuration.DefaultConfigurationBuilder;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.metrics.api.NoopMetricFactory;
 import org.junit.After;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -225,6 +227,10 @@ public class DNSJavaServiceTest {
 
     private final class TestableDNSServer extends DNSJavaService {
 
+        public TestableDNSServer() {
+            super(new NoopMetricFactory());
+        }
+
         public void setResolver(Resolver r) {
             resolver = r;
         }


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


[6/7] james-project git commit: JAMES-1983 Split WebAdmin to match orthogonal Guice architecture

Posted by bt...@apache.org.
JAMES-1983 Split WebAdmin to match orthogonal Guice architecture


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

Branch: refs/heads/master
Commit: cca0f39895d526cdf33a76987ecaafb8facc0d03
Parents: 6a8b56b
Author: benwa <bt...@linagora.com>
Authored: Sat Apr 1 00:22:32 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Sat Apr 1 15:24:29 2017 +0700

----------------------------------------------------------------------
 server/container/guice/cassandra-guice/pom.xml  |   8 +
 .../apache/james/CassandraJamesServerMain.java  |   6 +-
 server/container/guice/jpa-guice/pom.xml        |   8 +
 .../org/apache/james/JPAJamesServerMain.java    |   6 +-
 .../james/modules/server/NoJwtModule.java       |  34 -
 server/container/guice/jpa-smtp/pom.xml         |   8 +
 .../org/apache/james/JPAJamesServerMain.java    |   8 +-
 server/container/guice/memory-guice/pom.xml     |   8 +
 .../org/apache/james/MemoryJamesServerMain.java |   4 +
 server/container/guice/pom.xml                  |  12 +
 .../guice/protocols/webadmin-data/pom.xml       | 206 +++++
 .../james/modules/server/DataRoutesModules.java |  37 +
 .../guice/protocols/webadmin-mailbox/pom.xml    | 206 +++++
 .../modules/server/MailboxRoutesModule.java     |  37 +
 .../container/guice/protocols/webadmin/pom.xml  |   2 +-
 .../james/modules/server/NoJwtModule.java       |  34 +
 .../modules/server/WebAdminServerModule.java    |  11 -
 server/pom.xml                                  |  20 +-
 .../protocols/webadmin-integration-test/pom.xml |  12 +-
 server/protocols/webadmin/pom.xml               | 314 --------
 .../org/apache/james/webadmin/CORSFilter.java   |  40 -
 .../org/apache/james/webadmin/Constants.java    |  27 -
 .../org/apache/james/webadmin/FixedPort.java    |  54 --
 .../java/org/apache/james/webadmin/Port.java    |  26 -
 .../org/apache/james/webadmin/RandomPort.java   |  50 --
 .../java/org/apache/james/webadmin/Routes.java  |  28 -
 .../apache/james/webadmin/TlsConfiguration.java | 124 ---
 .../james/webadmin/WebAdminConfiguration.java   | 169 ----
 .../apache/james/webadmin/WebAdminServer.java   | 129 ---
 .../authentication/AuthenticationFilter.java    |  25 -
 .../webadmin/authentication/JwtFilter.java      |  76 --
 .../authentication/NoAuthenticationFilter.java  |  31 -
 .../james/webadmin/dto/AddUserRequest.java      |  39 -
 .../james/webadmin/dto/MailboxResponse.java     |  33 -
 .../org/apache/james/webadmin/dto/QuotaDTO.java |  73 --
 .../apache/james/webadmin/dto/QuotaRequest.java |  39 -
 .../apache/james/webadmin/dto/UserResponse.java |  33 -
 .../james/webadmin/metric/MetricPostFilter.java |  37 -
 .../james/webadmin/metric/MetricPreFilter.java  |  41 -
 .../apache/james/webadmin/routes/CORSRoute.java |  42 -
 .../james/webadmin/routes/DomainRoutes.java     | 118 ---
 .../webadmin/routes/GlobalQuotaRoutes.java      | 130 ----
 .../webadmin/routes/UserMailboxesRoutes.java    | 128 ---
 .../james/webadmin/routes/UserRoutes.java       | 104 ---
 .../webadmin/service/UserMailboxesService.java  | 143 ----
 .../james/webadmin/service/UserService.java     |  94 ---
 .../webadmin/utils/JsonExtractException.java    |  27 -
 .../james/webadmin/utils/JsonExtractor.java     |  44 --
 .../james/webadmin/utils/JsonTransformer.java   |  41 -
 .../utils/MailboxHaveChildrenException.java     |  27 -
 .../james/webadmin/validation/MailboxName.java  |  40 -
 .../apache/james/webadmin/FixedPortTest.java    |  57 --
 .../apache/james/webadmin/RandomPortTest.java   |  34 -
 .../james/webadmin/TlsConfigurationTest.java    |  88 ---
 .../webadmin/WebAdminConfigurationTest.java     | 181 -----
 .../webadmin/authentication/JwtFilterTest.java  | 124 ---
 .../james/webadmin/dto/QuotaRequestTest.java    |  59 --
 .../james/webadmin/routes/DomainRoutesTest.java | 326 --------
 .../webadmin/routes/GlobalQuotaRoutesTest.java  | 261 -------
 .../routes/UserMailboxesRoutesTest.java         | 779 ------------------
 .../james/webadmin/routes/UsersRoutesTest.java  | 422 ----------
 .../james/webadmin/utils/JsonExtractorTest.java | 114 ---
 server/protocols/webadmin/webadmin-core/pom.xml | 281 +++++++
 .../org/apache/james/webadmin/CORSFilter.java   |  40 +
 .../org/apache/james/webadmin/Constants.java    |  27 +
 .../org/apache/james/webadmin/FixedPort.java    |  54 ++
 .../java/org/apache/james/webadmin/Port.java    |  26 +
 .../org/apache/james/webadmin/RandomPort.java   |  50 ++
 .../java/org/apache/james/webadmin/Routes.java  |  28 +
 .../apache/james/webadmin/TlsConfiguration.java | 124 +++
 .../james/webadmin/WebAdminConfiguration.java   | 169 ++++
 .../apache/james/webadmin/WebAdminServer.java   | 129 +++
 .../authentication/AuthenticationFilter.java    |  25 +
 .../webadmin/authentication/JwtFilter.java      |  76 ++
 .../authentication/NoAuthenticationFilter.java  |  31 +
 .../james/webadmin/metric/MetricPostFilter.java |  37 +
 .../james/webadmin/metric/MetricPreFilter.java  |  41 +
 .../apache/james/webadmin/routes/CORSRoute.java |  42 +
 .../webadmin/utils/JsonExtractException.java    |  27 +
 .../james/webadmin/utils/JsonExtractor.java     |  44 ++
 .../james/webadmin/utils/JsonTransformer.java   |  41 +
 .../apache/james/webadmin/FixedPortTest.java    |  57 ++
 .../apache/james/webadmin/RandomPortTest.java   |  34 +
 .../james/webadmin/TlsConfigurationTest.java    |  88 +++
 .../webadmin/WebAdminConfigurationTest.java     | 181 +++++
 .../webadmin/authentication/JwtFilterTest.java  | 124 +++
 .../james/webadmin/utils/JsonExtractorTest.java | 114 +++
 server/protocols/webadmin/webadmin-data/pom.xml | 280 +++++++
 .../james/webadmin/dto/AddUserRequest.java      |  39 +
 .../apache/james/webadmin/dto/UserResponse.java |  33 +
 .../james/webadmin/routes/DomainRoutes.java     | 118 +++
 .../james/webadmin/routes/UserRoutes.java       | 104 +++
 .../james/webadmin/service/UserService.java     |  94 +++
 .../james/webadmin/routes/DomainRoutesTest.java | 326 ++++++++
 .../james/webadmin/routes/UsersRoutesTest.java  | 422 ++++++++++
 .../protocols/webadmin/webadmin-mailbox/pom.xml | 292 +++++++
 .../james/webadmin/dto/MailboxResponse.java     |  33 +
 .../org/apache/james/webadmin/dto/QuotaDTO.java |  73 ++
 .../apache/james/webadmin/dto/QuotaRequest.java |  39 +
 .../webadmin/routes/GlobalQuotaRoutes.java      | 130 ++++
 .../webadmin/routes/UserMailboxesRoutes.java    | 129 +++
 .../webadmin/service/UserMailboxesService.java  | 143 ++++
 .../utils/MailboxHaveChildrenException.java     |  27 +
 .../james/webadmin/validation/MailboxName.java  |  40 +
 .../james/webadmin/dto/QuotaRequestTest.java    |  59 ++
 .../webadmin/routes/GlobalQuotaRoutesTest.java  | 261 +++++++
 .../routes/UserMailboxesRoutesTest.java         | 780 +++++++++++++++++++
 107 files changed, 5925 insertions(+), 4825 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/cassandra-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/pom.xml b/server/container/guice/cassandra-guice/pom.xml
index 348003e..9e78b34 100644
--- a/server/container/guice/cassandra-guice/pom.xml
+++ b/server/container/guice/cassandra-guice/pom.xml
@@ -292,6 +292,14 @@
                     <artifactId>james-server-guice-webadmin</artifactId>
                 </dependency>
                 <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-guice-webadmin-data</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-guice-webadmin-mailbox</artifactId>
+                </dependency>
+                <dependency>
                     <groupId>${project.groupId}</groupId>
                     <artifactId>james-server-jmap-integration-testing</artifactId>
                     <type>test-jar</type>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
index 289106b..7cd4bb9 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
@@ -36,8 +36,10 @@ import org.apache.james.modules.protocols.POP3ServerModule;
 import org.apache.james.modules.protocols.ProtocolHandlerModule;
 import org.apache.james.modules.protocols.SMTPServerModule;
 import org.apache.james.modules.server.ActiveMQQueueModule;
+import org.apache.james.modules.server.DataRoutesModules;
 import org.apache.james.modules.server.ESMetricReporterModule;
 import org.apache.james.modules.server.JMXServerModule;
+import org.apache.james.modules.server.MailboxRoutesModule;
 import org.apache.james.modules.server.WebAdminServerModule;
 
 import com.google.inject.Module;
@@ -52,7 +54,9 @@ public class CassandraJamesServerMain {
             new SMTPServerModule(),
             new LMTPServerModule(),
             new ManageSieveServerModule(),
-            new WebAdminServerModule());
+            new WebAdminServerModule(),
+            new DataRoutesModules(),
+            new MailboxRoutesModule());
     
     public static final Module cassandraServerModule = Modules.combine(
         new JMAPServerModule(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/jpa-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/pom.xml b/server/container/guice/jpa-guice/pom.xml
index e70712e..fdc62ec 100644
--- a/server/container/guice/jpa-guice/pom.xml
+++ b/server/container/guice/jpa-guice/pom.xml
@@ -259,6 +259,14 @@
                 </dependency>
                 <dependency>
                     <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-webadmin-data</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-webadmin-mailbox</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
                     <artifactId>james-server-jpa-common-guice</artifactId>
                 </dependency>
                 <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java b/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
index 19a8430..1b64bb2 100644
--- a/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
+++ b/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
@@ -31,7 +31,9 @@ import org.apache.james.modules.protocols.POP3ServerModule;
 import org.apache.james.modules.protocols.ProtocolHandlerModule;
 import org.apache.james.modules.protocols.SMTPServerModule;
 import org.apache.james.modules.server.ActiveMQQueueModule;
+import org.apache.james.modules.server.DataRoutesModules;
 import org.apache.james.modules.server.JMXServerModule;
+import org.apache.james.modules.server.MailboxRoutesModule;
 import org.apache.james.modules.server.NoJwtModule;
 import org.apache.james.modules.server.RawPostDequeueDecoratorModule;
 import org.apache.james.modules.server.WebAdminServerModule;
@@ -48,7 +50,9 @@ public class JPAJamesServerMain {
             new SMTPServerModule(),
             new LMTPServerModule(),
             new ManageSieveServerModule(),
-            new WebAdminServerModule());
+            new WebAdminServerModule(),
+            new DataRoutesModules(),
+            new MailboxRoutesModule());
     
     public static final Module jpaServerModule = Modules.combine(
         new JPAMailboxModule(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/server/NoJwtModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/server/NoJwtModule.java b/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/server/NoJwtModule.java
deleted file mode 100644
index a500595..0000000
--- a/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/server/NoJwtModule.java
+++ /dev/null
@@ -1,34 +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.modules.server;
-
-import java.util.Optional;
-
-import org.apache.james.jwt.JwtConfiguration;
-
-import com.google.inject.AbstractModule;
-
-public class NoJwtModule extends AbstractModule {
-
-    @Override
-    protected void configure() {
-        bind(JwtConfiguration.class).toInstance(new JwtConfiguration(Optional.empty()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/jpa-smtp/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-smtp/pom.xml b/server/container/guice/jpa-smtp/pom.xml
index e10c620..4f2b161 100644
--- a/server/container/guice/jpa-smtp/pom.xml
+++ b/server/container/guice/jpa-smtp/pom.xml
@@ -222,6 +222,14 @@
                     <artifactId>james-server-jpa-common-guice</artifactId>
                 </dependency>
                 <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-guice-webadmin</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-guice-webadmin-data</artifactId>
+                </dependency>
+                <dependency>
                     <groupId>ch.qos.logback</groupId>
                     <artifactId>logback-classic</artifactId>
                     <version>1.1.7</version>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/jpa-smtp/src/main/java/org/apache/james/JPAJamesServerMain.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-smtp/src/main/java/org/apache/james/JPAJamesServerMain.java b/server/container/guice/jpa-smtp/src/main/java/org/apache/james/JPAJamesServerMain.java
index 51174c6..f8ebc93 100644
--- a/server/container/guice/jpa-smtp/src/main/java/org/apache/james/JPAJamesServerMain.java
+++ b/server/container/guice/jpa-smtp/src/main/java/org/apache/james/JPAJamesServerMain.java
@@ -25,7 +25,10 @@ import org.apache.james.modules.data.JPADataModule;
 import org.apache.james.modules.protocols.ProtocolHandlerModule;
 import org.apache.james.modules.protocols.SMTPServerModule;
 import org.apache.james.modules.server.ActiveMQQueueModule;
+import org.apache.james.modules.server.DataRoutesModules;
+import org.apache.james.modules.server.NoJwtModule;
 import org.apache.james.modules.server.RawPostDequeueDecoratorModule;
+import org.apache.james.modules.server.WebAdminServerModule;
 import org.apache.openjpa.persistence.OpenJPAPersistence;
 
 import com.google.inject.Module;
@@ -35,7 +38,10 @@ public class JPAJamesServerMain {
 
     public static final Module protocols = Modules.combine(
             new ProtocolHandlerModule(),
-            new SMTPServerModule());
+            new SMTPServerModule(),
+            new WebAdminServerModule(),
+            new DataRoutesModules(),
+            new NoJwtModule());
     
     public static final Module jpaServerModule = Modules.combine(
         new JPADataModule(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/memory-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/memory-guice/pom.xml b/server/container/guice/memory-guice/pom.xml
index 8496189..8cffde9 100644
--- a/server/container/guice/memory-guice/pom.xml
+++ b/server/container/guice/memory-guice/pom.xml
@@ -254,6 +254,14 @@
                 </dependency>
                 <dependency>
                     <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-webadmin-data</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-webadmin-mailbox</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
                     <artifactId>apache-mailet-base</artifactId>
                     <type>test-jar</type>
                     <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
----------------------------------------------------------------------
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
index 0cf291c..bfc412b 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
@@ -30,7 +30,9 @@ import org.apache.james.modules.protocols.ManageSieveServerModule;
 import org.apache.james.modules.protocols.POP3ServerModule;
 import org.apache.james.modules.protocols.ProtocolHandlerModule;
 import org.apache.james.modules.protocols.SMTPServerModule;
+import org.apache.james.modules.server.DataRoutesModules;
 import org.apache.james.modules.server.JMXServerModule;
+import org.apache.james.modules.server.MailboxRoutesModule;
 import org.apache.james.modules.server.MemoryMailQueueModule;
 import org.apache.james.modules.server.WebAdminServerModule;
 
@@ -48,6 +50,8 @@ public class MemoryJamesServerMain {
             new LMTPServerModule(),
             new ManageSieveServerModule(),
             new WebAdminServerModule(),
+            new DataRoutesModules(),
+            new MailboxRoutesModule(),
             new MemoryDataModule(),
             new MemoryDataJmapModule(),
             new MemoryMailboxModule(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/pom.xml b/server/container/guice/pom.xml
index bc00fd7..1d7a263 100644
--- a/server/container/guice/pom.xml
+++ b/server/container/guice/pom.xml
@@ -97,6 +97,16 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
+                <artifactId>james-server-guice-webadmin-data</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>james-server-guice-webadmin-mailbox</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
                 <artifactId>james-server-jpa-common-guice</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -123,6 +133,8 @@
         <module>protocols/pop</module>
         <module>protocols/smtp</module>
         <module>protocols/webadmin</module>
+        <module>protocols/webadmin-mailbox</module>
+        <module>protocols/webadmin-data</module>
     </modules>
 </project>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin-data/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-data/pom.xml b/server/container/guice/protocols/webadmin-data/pom.xml
new file mode 100644
index 0000000..a61d0c4
--- /dev/null
+++ b/server/container/guice/protocols/webadmin-data/pom.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>james-server-guice</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta6-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>james-server-guice-webadmin-data</artifactId>
+
+    <name>Apache James :: Server :: Guice :: Webadmin :: Data</name>
+    <description>Webadmin data modules for Guice implementation of James server</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+            <dependencies>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-configuration</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-data</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.inject</groupId>
+                    <artifactId>guice</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.inject.extensions</groupId>
+                    <artifactId>guice-multibindings</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin-data/src/main/java/org/apache/james/modules/server/DataRoutesModules.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-data/src/main/java/org/apache/james/modules/server/DataRoutesModules.java b/server/container/guice/protocols/webadmin-data/src/main/java/org/apache/james/modules/server/DataRoutesModules.java
new file mode 100644
index 0000000..3fb6669
--- /dev/null
+++ b/server/container/guice/protocols/webadmin-data/src/main/java/org/apache/james/modules/server/DataRoutesModules.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.modules.server;
+
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.routes.DomainRoutes;
+import org.apache.james.webadmin.routes.UserRoutes;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+
+public class DataRoutesModules extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        Multibinder<Routes> routesMultibinder = Multibinder.newSetBinder(binder(), Routes.class);
+        routesMultibinder.addBinding().to(DomainRoutes.class);
+        routesMultibinder.addBinding().to(UserRoutes.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-mailbox/pom.xml b/server/container/guice/protocols/webadmin-mailbox/pom.xml
new file mode 100644
index 0000000..2d8e49d
--- /dev/null
+++ b/server/container/guice/protocols/webadmin-mailbox/pom.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>james-server-guice</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta6-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>james-server-guice-webadmin-mailbox</artifactId>
+
+    <name>Apache James :: Server :: Guice :: Webadmin :: Mailbox</name>
+    <description>Webadmin mailbox modules for Guice implementation of James server</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+            <dependencies>
+                <dependency>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>james-server-guice-configuration</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-core</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-mailbox</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.inject</groupId>
+                    <artifactId>guice</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>com.google.inject.extensions</groupId>
+                    <artifactId>guice-multibindings</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
new file mode 100644
index 0000000..7faba1f
--- /dev/null
+++ b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.modules.server;
+
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.routes.GlobalQuotaRoutes;
+import org.apache.james.webadmin.routes.UserMailboxesRoutes;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+
+public class MailboxRoutesModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        Multibinder<Routes> routesMultibinder = Multibinder.newSetBinder(binder(), Routes.class);
+        routesMultibinder.addBinding().to(UserMailboxesRoutes.class);
+        routesMultibinder.addBinding().to(GlobalQuotaRoutes.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin/pom.xml b/server/container/guice/protocols/webadmin/pom.xml
index 9f33f23..b4d2a6d 100644
--- a/server/container/guice/protocols/webadmin/pom.xml
+++ b/server/container/guice/protocols/webadmin/pom.xml
@@ -155,7 +155,7 @@
                 </dependency>
                 <dependency>
                     <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-webadmin</artifactId>
+                    <artifactId>james-server-webadmin-core</artifactId>
                 </dependency>
                 <dependency>
                     <groupId>com.google.inject</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/NoJwtModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/NoJwtModule.java b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/NoJwtModule.java
new file mode 100644
index 0000000..a500595
--- /dev/null
+++ b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/NoJwtModule.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.modules.server;
+
+import java.util.Optional;
+
+import org.apache.james.jwt.JwtConfiguration;
+
+import com.google.inject.AbstractModule;
+
+public class NoJwtModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        bind(JwtConfiguration.class).toInstance(new JwtConfiguration(Optional.empty()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
index f3ed440..c7820cc 100644
--- a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
+++ b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
@@ -36,16 +36,11 @@ import org.apache.james.utils.PropertiesProvider;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.FixedPort;
 import org.apache.james.webadmin.TlsConfiguration;
-import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.WebAdminConfiguration;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.authentication.AuthenticationFilter;
 import org.apache.james.webadmin.authentication.JwtFilter;
 import org.apache.james.webadmin.authentication.NoAuthenticationFilter;
-import org.apache.james.webadmin.routes.DomainRoutes;
-import org.apache.james.webadmin.routes.GlobalQuotaRoutes;
-import org.apache.james.webadmin.routes.UserMailboxesRoutes;
-import org.apache.james.webadmin.routes.UserRoutes;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -77,12 +72,6 @@ public class WebAdminServerModule extends AbstractModule {
         bind(JsonTransformer.class).in(Scopes.SINGLETON);
         bind(WebAdminServer.class).in(Scopes.SINGLETON);
 
-        Multibinder<Routes> routesMultibinder = Multibinder.newSetBinder(binder(), Routes.class);
-        routesMultibinder.addBinding().to(DomainRoutes.class);
-        routesMultibinder.addBinding().to(UserRoutes.class);
-        routesMultibinder.addBinding().to(UserMailboxesRoutes.class);
-        routesMultibinder.addBinding().to(GlobalQuotaRoutes.class);
-
         Multibinder.newSetBinder(binder(), ConfigurationPerformer.class).addBinding().to(WebAdminServerModuleConfigurationPerformer.class);
         Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(WebAdminGuiceProbe.class);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index d7791ed..cfffd6f 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -95,21 +95,23 @@
         <module>protocols/protocols-imap4</module>
         <module>protocols/jmap</module>
         <module>protocols/jmap-integration-testing</module>
+        <module>protocols/jwt</module>
         <module>protocols/protocols-library</module>
         <module>protocols/protocols-lmtp</module>
         <module>protocols/protocols-managesieve</module>
         <module>protocols/protocols-pop3</module>
         <module>protocols/protocols-smtp</module>
+        <module>protocols/webadmin/webadmin-core</module>
+        <module>protocols/webadmin/webadmin-data</module>
+        <module>protocols/webadmin/webadmin-mailbox</module>
+        <module>protocols/webadmin-integration-test</module>
 
         <module>queue/queue-api</module>
         <module>queue/queue-file</module>
         <module>queue/queue-jms</module>
         <module>queue/queue-activemq</module>
-        <module>protocols/webadmin</module>
-        <module>protocols/webadmin-integration-test</module>
 
         <module>testing</module>
-        <module>protocols/jwt</module>
     </modules>
 
     <distributionManagement>
@@ -683,7 +685,17 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.james</groupId>
-                <artifactId>james-server-webadmin</artifactId>
+                <artifactId>james-server-webadmin-core</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.james</groupId>
+                <artifactId>james-server-webadmin-data</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.james</groupId>
+                <artifactId>james-server-webadmin-mailbox</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin-integration-test/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/pom.xml b/server/protocols/webadmin-integration-test/pom.xml
index 0817987..9a6ec14 100644
--- a/server/protocols/webadmin-integration-test/pom.xml
+++ b/server/protocols/webadmin-integration-test/pom.xml
@@ -172,7 +172,17 @@
                 </dependency>
                 <dependency>
                     <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-webadmin</artifactId>
+                    <artifactId>james-server-webadmin-core</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-data</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.james</groupId>
+                    <artifactId>james-server-webadmin-mailbox</artifactId>
                     <scope>test</scope>
                 </dependency>
                 <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/pom.xml b/server/protocols/webadmin/pom.xml
deleted file mode 100644
index 3703c7a..0000000
--- a/server/protocols/webadmin/pom.xml
+++ /dev/null
@@ -1,314 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <artifactId>james-server</artifactId>
-        <groupId>org.apache.james</groupId>
-        <version>3.0.0-beta6-SNAPSHOT</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>james-server-webadmin</artifactId>
-    <packaging>jar</packaging>
-
-    <name>Apache James :: Server :: Web Admin</name>
-
-    <profiles>
-        <profile>
-            <id>noTest</id>
-            <activation>
-                <os>
-                    <family>windows</family>
-                </os>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <skipTests>true</skipTests>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-        <profile>
-            <id>disable-build-for-older-jdk</id>
-            <activation>
-                <jdk>(,1.8)</jdk>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <artifactId>maven-jar-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-jar</id>
-                                <phase>none</phase>
-                            </execution>
-                            <execution>
-                                <id>jar</id>
-                                <phase>none</phase>
-                            </execution>
-                            <execution>
-                                <id>test-jar</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-compiler-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-compile</id>
-                                <phase>none</phase>
-                            </execution>
-                            <execution>
-                                <id>default-testCompile</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-test</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-source-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>attach-sources</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-install-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-install</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-resources-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-resources</id>
-                                <phase>none</phase>
-                            </execution>
-                            <execution>
-                                <id>default-testResources</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-site-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>attach-descriptor</id>
-                                <phase>none</phase>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-        <profile>
-            <id>build-for-jdk-8</id>
-            <activation>
-                <jdk>[1.8,)</jdk>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>apache-james-mailbox-api</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>apache-james-mailbox-memory</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-util-java8</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-lifecycle-api</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-jwt</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-data-api</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>james-server-data-memory</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>metrics-api</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.james</groupId>
-                    <artifactId>metrics-logger</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                    <artifactId>jackson-databind</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>com.github.fge</groupId>
-                    <artifactId>throwing-lambdas</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>com.google.guava</groupId>
-                    <artifactId>guava</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>com.jayway.restassured</groupId>
-                    <artifactId>rest-assured</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>com.sparkjava</groupId>
-                    <artifactId>spark-core</artifactId>
-                    <version>2.5.5</version>
-                </dependency>
-                <dependency>
-                    <groupId>de.bechte.junit</groupId>
-                    <artifactId>junit-hierarchicalcontextrunner</artifactId>
-                    <version>4.11.3</version>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>javax.inject</groupId>
-                    <artifactId>javax.inject</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>junit</groupId>
-                    <artifactId>junit</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.assertj</groupId>
-                    <artifactId>assertj-core</artifactId>
-                    <version>${assertj-3.version}</version>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.mockito</groupId>
-                    <artifactId>mockito-core</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.hamcrest</groupId>
-                    <artifactId>java-hamcrest</artifactId>
-                    <scope>test</scope>
-                </dependency>
-                <dependency>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-api</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>nl.jqno.equalsverifier</groupId>
-                    <artifactId>equalsverifier</artifactId>
-                    <version>1.7.6</version>
-                </dependency>
-                <dependency>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>slf4j-simple</artifactId>
-                    <scope>test</scope>
-                </dependency>
-            </dependencies>
-            <build>
-                <plugins>
-                    <plugin>
-                        <artifactId>maven-assembly-plugin</artifactId>
-                        <configuration>
-                            <archive>
-                                <manifest>
-                                    <mainClass>fully.qualified.MainClass</mainClass>
-                                </manifest>
-                            </archive>
-                            <descriptorRefs>
-                                <descriptorRef>jar-with-dependencies</descriptorRef>
-                            </descriptorRefs>
-                        </configuration>
-                    </plugin>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-compiler-plugin</artifactId>
-                        <configuration>
-                            <source>1.8</source>
-                            <target>1.8</target>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-        <profile>
-            <id>animal-sniffer-java-8</id>
-            <activation>
-                <jdk>[1.8,)</jdk>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>animal-sniffer-maven-plugin</artifactId>
-                        <configuration>
-                            <signature>
-                                <groupId>org.codehaus.mojo.signature</groupId>
-                                <artifactId>java18</artifactId>
-                                <version>1.0</version>
-                            </signature>
-                        </configuration>
-                        <executions>
-                            <execution>
-                                <id>check_java_8</id>
-                                <phase>test</phase>
-                                <goals>
-                                    <goal>check</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
-</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/CORSFilter.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/CORSFilter.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/CORSFilter.java
deleted file mode 100644
index c4cfb29..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/CORSFilter.java
+++ /dev/null
@@ -1,40 +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.webadmin;
-
-import spark.Filter;
-import spark.Request;
-import spark.Response;
-
-
-public class CORSFilter implements Filter {
-    private final String urlCORSOrigin;
-
-    public CORSFilter(String urlCORSOrigin) {
-        this.urlCORSOrigin = urlCORSOrigin;
-    }
-
-    @Override
-    public void handle(Request request, Response response) throws Exception {
-            response.header("Access-Control-Allow-Origin", urlCORSOrigin);
-            response.header("Access-Control-Request-Method", "DELETE, GET, POST, PUT");
-            response.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Constants.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Constants.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Constants.java
deleted file mode 100644
index 1031a86..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Constants.java
+++ /dev/null
@@ -1,27 +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.webadmin;
-
-public interface Constants {
-
-    String SEPARATOR = "/";
-    String EMPTY_BODY = "";
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/FixedPort.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/FixedPort.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/FixedPort.java
deleted file mode 100644
index 7ada8a1..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/FixedPort.java
+++ /dev/null
@@ -1,54 +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.webadmin;
-
-import java.util.Objects;
-
-import com.google.common.base.Preconditions;
-
-public class FixedPort implements Port {
-
-    private final int port;
-
-    public FixedPort(int port) {
-        Preconditions.checkArgument(port > 0 && port < 65536, "Port should be strictly contained between 0 and 65536");
-        this.port = port;
-    }
-
-    @Override
-    public int toInt() {
-        return port;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof FixedPort) {
-            FixedPort that = (FixedPort) o;
-
-            return Objects.equals(this.port, that.port);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(port);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Port.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Port.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Port.java
deleted file mode 100644
index ff7a50b..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Port.java
+++ /dev/null
@@ -1,26 +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.webadmin;
-
-public interface Port {
-
-    int toInt();
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/RandomPort.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/RandomPort.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/RandomPort.java
deleted file mode 100644
index 2b3ab5d..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/RandomPort.java
+++ /dev/null
@@ -1,50 +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.webadmin;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.base.Throwables;
-
-public class RandomPort implements Port {
-
-    public static int findFreePort() {
-        try (ServerSocket socket = new ServerSocket(0)) {
-            return socket.getLocalPort();
-        } catch (IOException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-    private final Supplier<Integer> portSupplier;
-
-    public RandomPort() {
-        portSupplier = Suppliers.memoize(RandomPort::findFreePort);
-    }
-
-    @Override
-    public int toInt() {
-        return portSupplier.get();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Routes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Routes.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Routes.java
deleted file mode 100644
index bc8554a..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/Routes.java
+++ /dev/null
@@ -1,28 +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.webadmin;
-
-import spark.Service;
-
-public interface Routes {
-
-    void define(Service service);
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/cca0f398/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/TlsConfiguration.java b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
deleted file mode 100644
index d549ea3..0000000
--- a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/TlsConfiguration.java
+++ /dev/null
@@ -1,124 +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.webadmin;
-
-import java.util.Objects;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-
-public class TlsConfiguration {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-        private String keystoreFilePath;
-        private String keystorePassword;
-        private String truststoreFilePath;
-        private String truststorePassword;
-
-        public Builder raw(String keystoreFilePath,
-                           String keystorePassword,
-                           String truststoreFilePath,
-                           String truststorePassword){
-            Preconditions.checkNotNull(keystoreFilePath);
-            Preconditions.checkNotNull(keystorePassword);
-
-            this.keystoreFilePath = keystoreFilePath;
-            this.keystorePassword = keystorePassword;
-            this.truststoreFilePath = truststoreFilePath;
-            this.truststorePassword = truststorePassword;
-            return this;
-        }
-
-        public Builder selfSigned(String keystoreFilePath, String keystorePassword){
-            Preconditions.checkNotNull(keystoreFilePath);
-            Preconditions.checkNotNull(keystorePassword);
-
-            this.keystoreFilePath = keystoreFilePath;
-            this.keystorePassword = keystorePassword;
-            return this;
-        }
-
-        public TlsConfiguration build() {
-            Preconditions.checkState(hasKeystoreInformation(), "If enabled, you need to provide keystore information");
-            Preconditions.checkState(optionalHasTrustStoreInformation(), "You need to provide both information about trustStore");
-            return new TlsConfiguration(keystoreFilePath, keystorePassword, truststoreFilePath, truststorePassword);
-        }
-
-        private boolean optionalHasTrustStoreInformation() {
-            return (truststoreFilePath == null) == (truststorePassword == null);
-        }
-
-        private boolean hasKeystoreInformation() {
-            return keystorePassword != null && keystoreFilePath != null;
-        }
-
-    }
-
-    private final String keystoreFilePath;
-    private final String keystorePassword;
-    private final String truststoreFilePath;
-    private final String truststorePassword;
-
-    @VisibleForTesting
-    TlsConfiguration(String keystoreFilePath, String keystorePassword, String truststoreFilePath, String truststorePassword) {
-        this.keystoreFilePath = keystoreFilePath;
-        this.keystorePassword = keystorePassword;
-        this.truststoreFilePath = truststoreFilePath;
-        this.truststorePassword = truststorePassword;
-    }
-
-    public String getKeystoreFilePath() {
-        return keystoreFilePath;
-    }
-
-    public String getKeystorePassword() {
-        return keystorePassword;
-    }
-
-    public String getTruststoreFilePath() {
-        return truststoreFilePath;
-    }
-
-    public String getTruststorePassword() {
-        return truststorePassword;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-       if (o instanceof TlsConfiguration) {
-           TlsConfiguration that = (TlsConfiguration) o;
-
-           return Objects.equals(this.keystoreFilePath, that.keystoreFilePath)
-               && Objects.equals(this.keystorePassword, that.keystorePassword)
-               && Objects.equals(this.truststoreFilePath, that.truststoreFilePath)
-               && Objects.equals(this.truststorePassword, that.truststorePassword);
-       }
-       return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(keystoreFilePath, keystorePassword, truststoreFilePath, truststorePassword);
-    }
-}


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