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 2018/03/15 09:14:18 UTC
[08/18] james-project git commit: JAMES-2344 implement per domain
quota. Wiring to user quota missing
JAMES-2344 implement per domain quota. Wiring to user quota missing
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5191b5fa
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5191b5fa
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5191b5fa
Branch: refs/heads/master
Commit: 5191b5fa998e364f08beb203b9a9dc2371da4a7c
Parents: 79876e3
Author: Matthieu Baechler <ma...@apache.org>
Authored: Mon Mar 12 17:24:51 2018 +0100
Committer: benwa <bt...@linagora.com>
Committed: Thu Mar 15 14:40:15 2018 +0700
----------------------------------------------------------------------
.../org/apache/james/mailbox/model/Quota.java | 1 +
.../james/mailbox/quota/MaxQuotaManager.java | 12 +
.../cassandra/modules/CassandraQuotaModule.java | 11 +
.../quota/CassandraPerDomainMaxQuotaDao.java | 134 ++++++
.../quota/CassandraPerUserMaxQuotaManager.java | 37 +-
.../table/CassandraDomainMaxQuota.java | 28 ++
.../cassandra/CassandraTestSystemFixture.java | 2 +
.../CassandraPerUserMaxQuotaManagerTest.java | 1 +
.../jpa/quota/JPAPerUserMaxQuotaDAO.java | 55 +++
.../jpa/quota/JPAPerUserMaxQuotaManager.java | 31 ++
.../jpa/quota/model/MaxDomainMessageCount.java | 52 +++
.../jpa/quota/model/MaxDomainStorage.java | 53 +++
.../james/mailbox/jpa/JPAMailboxFixture.java | 6 +
.../quota/InMemoryPerUserMaxQuotaManager.java | 37 +-
.../store/quota/FixedMaxQuotaManager.java | 34 ++
.../mailbox/store/quota/NoMaxQuotaManager.java | 30 ++
.../store/quota/GenericMaxQuotaManagerTest.java | 98 ++++-
.../cassandra/host/CassandraHostSystem.java | 2 +
.../modules/mailbox/CassandraQuotaModule.java | 2 +
.../webadmin/routes/DomainQuotaRoutes.java | 297 +++++++++++++
.../webadmin/routes/DomainQuotaService.java | 81 ++++
.../webadmin/routes/DomainQuotaRoutesTest.java | 430 +++++++++++++++++++
22 files changed, 1430 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java
index dd82bd2..cabd05a 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java
@@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableMap;
public class Quota<T extends QuotaValue<T>> {
public enum Scope {
+ Domain,
Global,
User
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
index 81814cc..830a81a 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
@@ -121,4 +121,16 @@ public interface MaxQuotaManager {
Map<Quota.Scope, QuotaCount> listMaxMessagesDetails(QuotaRoot quotaRoot);
Map<Quota.Scope, QuotaSize> listMaxStorageDetails(QuotaRoot quotaRoot);
+
+ Optional<QuotaCount> getDomainMaxMessage(String domain);
+
+ void setDomainMaxMessage(String domain, QuotaCount count) throws MailboxException;
+
+ void removeDomainMaxMessage(String domain) throws MailboxException;
+
+ void setDomainMaxStorage(String domain, QuotaSize size) throws MailboxException;
+
+ Optional<QuotaSize> getDomainMaxStorage(String domain);
+
+ void removeDomainMaxStorage(String domain) throws MailboxException;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraQuotaModule.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraQuotaModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraQuotaModule.java
index 32a963c..4598fb9 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraQuotaModule.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraQuotaModule.java
@@ -31,6 +31,7 @@ import org.apache.james.backends.cassandra.components.CassandraType;
import org.apache.james.backends.cassandra.utils.CassandraConstants;
import org.apache.james.mailbox.cassandra.table.CassandraCurrentQuota;
import org.apache.james.mailbox.cassandra.table.CassandraDefaultMaxQuota;
+import org.apache.james.mailbox.cassandra.table.CassandraDomainMaxQuota;
import org.apache.james.mailbox.cassandra.table.CassandraMaxQuota;
import com.datastax.driver.core.schemabuilder.SchemaBuilder;
@@ -63,6 +64,16 @@ public class CassandraQuotaModule implements CassandraModule {
.comment("Holds per quota-root limitations. Limitations can concern the number of messages in a quota-root or the total size of a quota-root.")
.caching(SchemaBuilder.KeyCaching.ALL,
SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION))),
+ new CassandraTable(CassandraDomainMaxQuota.TABLE_NAME,
+ SchemaBuilder.createTable(CassandraDomainMaxQuota.TABLE_NAME)
+ .ifNotExists()
+ .addPartitionKey(CassandraDomainMaxQuota.DOMAIN, text())
+ .addColumn(CassandraDomainMaxQuota.MESSAGE_COUNT, bigint())
+ .addColumn(CassandraDomainMaxQuota.STORAGE, bigint())
+ .withOptions()
+ .comment("Holds per domain limitations. Limitations can concern the number of messages in a quota-root or the total size of a quota-root.")
+ .caching(SchemaBuilder.KeyCaching.ALL,
+ SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION))),
new CassandraTable(CassandraDefaultMaxQuota.TABLE_NAME,
SchemaBuilder.createTable(CassandraDefaultMaxQuota.TABLE_NAME)
.ifNotExists()
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerDomainMaxQuotaDao.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerDomainMaxQuotaDao.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerDomainMaxQuotaDao.java
new file mode 100644
index 0000000..1f28f4c
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerDomainMaxQuotaDao.java
@@ -0,0 +1,134 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.cassandra.table.CassandraDomainMaxQuota;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.Delete;
+import com.datastax.driver.core.querybuilder.Insert;
+import com.datastax.driver.core.querybuilder.Select;
+
+public class CassandraPerDomainMaxQuotaDao {
+
+ private final Session session;
+ private final PreparedStatement setMaxStorageStatement;
+ private final PreparedStatement setMaxMessageStatement;
+ private final PreparedStatement getMaxStorageStatement;
+ private final PreparedStatement getMaxMessageStatement;
+ private final PreparedStatement removeMaxStorageStatement;
+ private final PreparedStatement removeMaxMessageStatement;
+
+ @Inject
+ public CassandraPerDomainMaxQuotaDao(Session session) {
+ this.session = session;
+ this.setMaxStorageStatement = session.prepare(setMaxStorageStatement());
+ this.setMaxMessageStatement = session.prepare(setMaxMessageStatement());
+ this.getMaxStorageStatement = session.prepare(getMaxStorageStatement());
+ this.getMaxMessageStatement = session.prepare(getMaxMessageStatement());
+ this.removeMaxStorageStatement = session.prepare(removeMaxStorageStatement());
+ this.removeMaxMessageStatement = session.prepare(removeMaxMessageStatement());
+ }
+
+ private Delete.Where removeMaxMessageStatement() {
+ return delete().column(CassandraDomainMaxQuota.MESSAGE_COUNT)
+ .from(CassandraDomainMaxQuota.TABLE_NAME)
+ .where(eq(CassandraDomainMaxQuota.DOMAIN, bindMarker()));
+ }
+
+ private Delete.Where removeMaxStorageStatement() {
+ return delete().column(CassandraDomainMaxQuota.STORAGE)
+ .from(CassandraDomainMaxQuota.TABLE_NAME)
+ .where(eq(CassandraDomainMaxQuota.DOMAIN, bindMarker()));
+ }
+
+ private Select.Where getMaxMessageStatement() {
+ return select(CassandraDomainMaxQuota.MESSAGE_COUNT)
+ .from(CassandraDomainMaxQuota.TABLE_NAME)
+ .where(eq(CassandraDomainMaxQuota.DOMAIN, bindMarker()));
+ }
+
+ private Select.Where getMaxStorageStatement() {
+ return select(CassandraDomainMaxQuota.STORAGE)
+ .from(CassandraDomainMaxQuota.TABLE_NAME)
+ .where(eq(CassandraDomainMaxQuota.DOMAIN, bindMarker()));
+ }
+
+ private Insert setMaxMessageStatement() {
+ return insertInto(CassandraDomainMaxQuota.TABLE_NAME)
+ .value(CassandraDomainMaxQuota.DOMAIN, bindMarker())
+ .value(CassandraDomainMaxQuota.MESSAGE_COUNT, bindMarker());
+ }
+
+ private Insert setMaxStorageStatement() {
+ return insertInto(CassandraDomainMaxQuota.TABLE_NAME)
+ .value(CassandraDomainMaxQuota.DOMAIN, bindMarker())
+ .value(CassandraDomainMaxQuota.STORAGE, bindMarker());
+ }
+
+ public void setMaxStorage(String domain, QuotaSize maxStorageQuota) {
+ session.execute(setMaxStorageStatement.bind(domain, QuotaCodec.quotaValueToLong(maxStorageQuota)));
+ }
+
+ public void setMaxMessage(String domain, QuotaCount maxMessageCount) {
+ session.execute(setMaxMessageStatement.bind(domain, QuotaCodec.quotaValueToLong(maxMessageCount)));
+ }
+
+ public Optional<QuotaSize> getMaxStorage(String domain) {
+ ResultSet resultSet = session.execute(getMaxStorageStatement.bind(domain));
+ if (resultSet.isExhausted()) {
+ return Optional.empty();
+ }
+ Long maxStorage = resultSet.one().get(CassandraDomainMaxQuota.STORAGE, Long.class);
+ return QuotaCodec.longToQuotaSize(maxStorage);
+ }
+
+ public Optional<QuotaCount> getMaxMessage(String domain) {
+ ResultSet resultSet = session.execute(getMaxMessageStatement.bind(domain));
+ if (resultSet.isExhausted()) {
+ return Optional.empty();
+ }
+ Long maxMessages = resultSet.one().get(CassandraDomainMaxQuota.MESSAGE_COUNT, Long.class);
+ return QuotaCodec.longToQuotaCount(maxMessages);
+ }
+
+ public void removeMaxMessage(String domain) {
+ session.execute(removeMaxMessageStatement.bind(domain));
+ }
+
+ public void removeMaxStorage(String domain) {
+ session.execute(removeMaxStorageStatement.bind(domain));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
index 05147bd..5b151e3 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import javax.inject.Inject;
import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.Quota;
import org.apache.james.mailbox.model.QuotaRoot;
import org.apache.james.mailbox.quota.MaxQuotaManager;
@@ -38,11 +39,15 @@ import com.github.steveash.guavate.Guavate;
public class CassandraPerUserMaxQuotaManager implements MaxQuotaManager {
private final CassandraPerUserMaxQuotaDao perUserQuota;
+ private final CassandraPerDomainMaxQuotaDao perDomainQuota;
private final CassandraDefaultMaxQuotaDao defaultQuota;
@Inject
- public CassandraPerUserMaxQuotaManager(CassandraPerUserMaxQuotaDao perUserQuota, CassandraDefaultMaxQuotaDao defaultQuota) {
+ public CassandraPerUserMaxQuotaManager(CassandraPerUserMaxQuotaDao perUserQuota,
+ CassandraPerDomainMaxQuotaDao domainQuota,
+ CassandraDefaultMaxQuotaDao defaultQuota) {
this.perUserQuota = perUserQuota;
+ this.perDomainQuota = domainQuota;
this.defaultQuota = defaultQuota;
}
@@ -57,6 +62,36 @@ public class CassandraPerUserMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public void setDomainMaxMessage(String domain, QuotaCount count) {
+ perDomainQuota.setMaxMessage(domain, count);
+ }
+
+ @Override
+ public void setDomainMaxStorage(String domain, QuotaSize size) {
+ perDomainQuota.setMaxStorage(domain, size);
+ }
+
+ @Override
+ public void removeDomainMaxMessage(String domain) throws MailboxException {
+ perDomainQuota.removeMaxMessage(domain);
+ }
+
+ @Override
+ public void removeDomainMaxStorage(String domain) {
+ perDomainQuota.removeMaxStorage(domain);
+ }
+
+ @Override
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ return perDomainQuota.getMaxMessage(domain);
+ }
+
+ @Override
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ return perDomainQuota.getMaxStorage(domain);
+ }
+
+ @Override
public void removeMaxMessage(QuotaRoot quotaRoot) {
perUserQuota.removeMaxMessage(quotaRoot);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDomainMaxQuota.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDomainMaxQuota.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDomainMaxQuota.java
new file mode 100644
index 0000000..66372f8
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDomainMaxQuota.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.mailbox.cassandra.table;
+
+public interface CassandraDomainMaxQuota {
+ String TABLE_NAME = "domainMaxQuota";
+
+ String DOMAIN = "domain";
+ String MESSAGE_COUNT = "maxMessageCount";
+ String STORAGE = "maxStorage";
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index 8fffb69..f396b81 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -27,6 +27,7 @@ import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManager;
import org.apache.james.mailbox.cassandra.quota.CassandraDefaultMaxQuotaDao;
+import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
import org.apache.james.mailbox.quota.CurrentQuotaManager;
@@ -84,6 +85,7 @@ public class CassandraTestSystemFixture {
public static MaxQuotaManager createMaxQuotaManager(CassandraCluster cassandra) {
return new CassandraPerUserMaxQuotaManager(
new CassandraPerUserMaxQuotaDao(cassandra.getConf()),
+ new CassandraPerDomainMaxQuotaDao(cassandra.getConf()),
new CassandraDefaultMaxQuotaDao(cassandra.getConf()));
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManagerTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManagerTest.java
index 35e495c..0f351ac 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManagerTest.java
@@ -38,6 +38,7 @@ public class CassandraPerUserMaxQuotaManagerTest extends GenericMaxQuotaManagerT
cassandra = CassandraCluster.create(new CassandraQuotaModule(), cassandraServer.getIp(), cassandraServer.getBindingPort());
return new CassandraPerUserMaxQuotaManager(
new CassandraPerUserMaxQuotaDao(cassandra.getConf()),
+ new CassandraPerDomainMaxQuotaDao(cassandra.getConf()),
new CassandraDefaultMaxQuotaDao(cassandra.getConf()));
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
index d29db8a..ab46ff9 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
@@ -28,6 +28,8 @@ import javax.persistence.EntityManagerFactory;
import org.apache.james.mailbox.jpa.quota.model.MaxDefaultMessageCount;
import org.apache.james.mailbox.jpa.quota.model.MaxDefaultStorage;
+import org.apache.james.mailbox.jpa.quota.model.MaxDomainMessageCount;
+import org.apache.james.mailbox.jpa.quota.model.MaxDomainStorage;
import org.apache.james.mailbox.jpa.quota.model.MaxUserMessageCount;
import org.apache.james.mailbox.jpa.quota.model.MaxUserStorage;
import org.apache.james.mailbox.model.QuotaRoot;
@@ -79,6 +81,42 @@ public class JPAPerUserMaxQuotaDAO {
return storedValue;
}
+ public void setDomainMaxMessage(String domain, Optional<QuotaCount> count) {
+ entityManager.getTransaction().begin();
+ MaxDomainMessageCount storedValue = getMaxDomainMessageEntity(domain, count);
+ entityManager.persist(storedValue);
+ entityManager.getTransaction().commit();
+ }
+
+
+ public void setDomainMaxStorage(String domain, Optional<QuotaSize> size) {
+ entityManager.getTransaction().begin();
+ MaxDomainStorage storedValue = getMaxDomainStorageEntity(domain, size);
+ entityManager.persist(storedValue);
+ entityManager.getTransaction().commit();
+ }
+
+ private MaxDomainMessageCount getMaxDomainMessageEntity(String domain, Optional<QuotaCount> maxMessageQuota) {
+ MaxDomainMessageCount storedValue = entityManager.find(MaxDomainMessageCount.class, domain);
+ Long value = quotaValueToLong(maxMessageQuota);
+ if (storedValue == null) {
+ return new MaxDomainMessageCount(domain, value);
+ }
+ storedValue.setValue(value);
+ return storedValue;
+ }
+
+ private MaxDomainStorage getMaxDomainStorageEntity(String domain, Optional<QuotaSize> maxStorageQuota) {
+ MaxDomainStorage storedValue = entityManager.find(MaxDomainStorage.class, domain);
+ Long value = quotaValueToLong(maxStorageQuota);
+ if (storedValue == null) {
+ return new MaxDomainStorage(domain, value);
+ }
+ storedValue.setValue(value);
+ return storedValue;
+ }
+
+
public void setDefaultMaxStorage(Optional<QuotaSize> defaultMaxStorage) {
entityManager.getTransaction().begin();
MaxDefaultStorage defaultMaxStorageEntity = getDefaultMaxStorageEntity(defaultMaxStorage);
@@ -145,6 +183,22 @@ public class JPAPerUserMaxQuotaDAO {
return longToQuotaCount(storedValue.getValue());
}
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ MaxDomainMessageCount storedValue = entityManager.find(MaxDomainMessageCount.class, domain);
+ if (storedValue == null) {
+ return Optional.empty();
+ }
+ return longToQuotaCount(storedValue.getValue());
+ }
+
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ MaxDomainStorage storedValue = entityManager.find(MaxDomainStorage.class, domain);
+ if (storedValue == null) {
+ return Optional.empty();
+ }
+ return longToQuotaSize(storedValue.getValue());
+ }
+
private Long quotaValueToLong(Optional<? extends QuotaValue<?>> maxStorageQuota) {
return maxStorageQuota.map(value -> {
@@ -172,4 +226,5 @@ public class JPAPerUserMaxQuotaDAO {
}
return Optional.of(quotaFactory.apply(value));
}
+
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaManager.java
index ef509cb..402ea4b 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaManager.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import javax.inject.Inject;
import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.Quota;
import org.apache.james.mailbox.model.QuotaRoot;
import org.apache.james.mailbox.quota.MaxQuotaManager;
@@ -54,6 +55,36 @@ public class JPAPerUserMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public void setDomainMaxMessage(String domain, QuotaCount count) {
+ dao.setDomainMaxMessage(domain, Optional.of(count));
+ }
+
+ @Override
+ public void setDomainMaxStorage(String domain, QuotaSize size) {
+ dao.setDomainMaxStorage(domain, Optional.of(size));
+ }
+
+ @Override
+ public void removeDomainMaxMessage(String domain) throws MailboxException {
+ dao.setDomainMaxMessage(domain, Optional.empty());
+ }
+
+ @Override
+ public void removeDomainMaxStorage(String domain) {
+ dao.setDomainMaxStorage(domain, Optional.empty());
+ }
+
+ @Override
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ return dao.getDomainMaxMessage(domain);
+ }
+
+ @Override
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ return dao.getDomainMaxStorage(domain);
+ }
+
+ @Override
public void removeMaxMessage(QuotaRoot quotaRoot) {
dao.setMaxMessage(quotaRoot, Optional.empty());
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainMessageCount.java
----------------------------------------------------------------------
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainMessageCount.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainMessageCount.java
new file mode 100644
index 0000000..eccae16
--- /dev/null
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainMessageCount.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.mailbox.jpa.quota.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity(name = "MaxDomainMessageCount")
+@Table(name = "JAMES_MAX_DOMAIN_MESSAGE_COUNT")
+public class MaxDomainMessageCount {
+ @Id
+ @Column(name = "DOMAIN")
+ private String domain;
+
+ @Column(name = "VALUE", nullable = true)
+ private Long value;
+
+ public MaxDomainMessageCount(String domain, Long value) {
+ this.domain = domain;
+ this.value = value;
+ }
+
+ public MaxDomainMessageCount() {
+ }
+
+ public Long getValue() {
+ return value;
+ }
+
+ public void setValue(Long value) {
+ this.value = value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainStorage.java
----------------------------------------------------------------------
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainStorage.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainStorage.java
new file mode 100644
index 0000000..3785306
--- /dev/null
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/model/MaxDomainStorage.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * 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.mailbox.jpa.quota.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity(name = "MaxDomainStorage")
+@Table(name = "JAMES_MAX_DOMAIN_STORAGE")
+public class MaxDomainStorage {
+
+ @Id
+ @Column(name = "DOMAIN")
+ private String domain;
+
+ @Column(name = "VALUE", nullable = true)
+ private Long value;
+
+ public MaxDomainStorage(String domain, Long value) {
+ this.domain = domain;
+ this.value = value;
+ }
+
+ public MaxDomainStorage() {
+ }
+
+ public Long getValue() {
+ return value;
+ }
+
+ public void setValue(Long value) {
+ this.value = value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxFixture.java
----------------------------------------------------------------------
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxFixture.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxFixture.java
index c0f955a..056e5dd 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxFixture.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxFixture.java
@@ -30,6 +30,8 @@ import org.apache.james.mailbox.jpa.mail.model.openjpa.JPAMailboxMessage;
import org.apache.james.mailbox.jpa.quota.model.JpaCurrentQuota;
import org.apache.james.mailbox.jpa.quota.model.MaxDefaultMessageCount;
import org.apache.james.mailbox.jpa.quota.model.MaxDefaultStorage;
+import org.apache.james.mailbox.jpa.quota.model.MaxDomainMessageCount;
+import org.apache.james.mailbox.jpa.quota.model.MaxDomainStorage;
import org.apache.james.mailbox.jpa.quota.model.MaxUserMessageCount;
import org.apache.james.mailbox.jpa.quota.model.MaxUserStorage;
import org.apache.james.mailbox.jpa.user.model.JPASubscription;
@@ -51,6 +53,8 @@ public interface JPAMailboxFixture {
List<Class<?>> QUOTA_PERSISTANCE_CLASSES = ImmutableList.<Class<?>>of(
MaxDefaultMessageCount.class,
MaxDefaultStorage.class,
+ MaxDomainStorage.class,
+ MaxDomainMessageCount.class,
MaxUserMessageCount.class,
MaxUserStorage.class,
JpaCurrentQuota.class
@@ -69,6 +73,8 @@ public interface JPAMailboxFixture {
"JAMES_MAX_DEFAULT_STORAGE",
"JAMES_MAX_USER_MESSAGE_COUNT",
"JAMES_MAX_USER_STORAGE",
+ "JAMES_MAX_DOMAIN_MESSAGE_COUNT",
+ "JAMES_MAX_DOMAIN_STORAGE",
"JAMES_QUOTA_CURRENTQUOTA"
);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryPerUserMaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryPerUserMaxQuotaManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryPerUserMaxQuotaManager.java
index aff15b9..1026cd5 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryPerUserMaxQuotaManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryPerUserMaxQuotaManager.java
@@ -38,6 +38,9 @@ public class InMemoryPerUserMaxQuotaManager implements MaxQuotaManager {
private Optional<QuotaCount> maxMessage = Optional.empty();
private Optional<QuotaSize> maxStorage = Optional.empty();
+ private final Map<String, QuotaCount> domainMaxMessage = new ConcurrentHashMap<>();
+ private final Map<String, QuotaSize> domainMaxStorage = new ConcurrentHashMap<>();
+
private final Map<String, QuotaSize> userMaxStorage = new ConcurrentHashMap<>();
private final Map<String, QuotaCount> userMaxMessage = new ConcurrentHashMap<>();
@@ -47,8 +50,23 @@ public class InMemoryPerUserMaxQuotaManager implements MaxQuotaManager {
}
@Override
- public void setDefaultMaxMessage(QuotaCount maxMessage) throws MailboxException {
- this.maxMessage = Optional.of(maxMessage);
+ public void setDomainMaxMessage(String domain, QuotaCount count) {
+ domainMaxMessage.put(domain, count);
+ }
+
+ @Override
+ public void setDomainMaxStorage(String domain, QuotaSize size) {
+ domainMaxStorage.put(domain, size);
+ }
+
+ @Override
+ public void removeDomainMaxMessage(String domain) throws MailboxException {
+ domainMaxMessage.remove(domain);
+ }
+
+ @Override
+ public void removeDomainMaxStorage(String domain) {
+ domainMaxStorage.remove(domain);
}
@Override
@@ -88,6 +106,21 @@ public class InMemoryPerUserMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public void setDefaultMaxMessage(QuotaCount maxMessage) throws MailboxException {
+ this.maxMessage = Optional.of(maxMessage);
+ }
+
+ @Override
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ return Optional.ofNullable(domainMaxMessage.get(domain));
+ }
+
+ @Override
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ return Optional.ofNullable(domainMaxStorage.get(domain));
+ }
+
+ @Override
public void setMaxStorage(QuotaRoot user, QuotaSize maxStorageQuota) {
userMaxStorage.put(user.getValue(), maxStorageQuota);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/FixedMaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/FixedMaxQuotaManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/FixedMaxQuotaManager.java
index e4ada35..6190820 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/FixedMaxQuotaManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/FixedMaxQuotaManager.java
@@ -44,6 +44,16 @@ public class FixedMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public void setDomainMaxMessage(String domain, QuotaCount count) throws MailboxException {
+ throw new UnsupportedOperationException("Can not modify domain specific upper limit for FixedMaxQuotaManager");
+ }
+
+ @Override
+ public void setDomainMaxStorage(String domain, QuotaSize size) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Can not modify domain specific upper limit for FixedMaxQuotaManager");
+ }
+
+ @Override
public void setDefaultMaxStorage(QuotaSize defaultMaxStorage) {
maxStorage = Optional.of(defaultMaxStorage);
}
@@ -88,6 +98,30 @@ public class FixedMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ return Optional.empty();
+ }
+
+ public Optional<QuotaCount> getMaxMessage() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void removeDomainMaxMessage(String domain) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Can not modify domain specific upper limit for FixedMaxQuotaManager");
+ }
+
+ @Override
+ public void removeDomainMaxStorage(String domain) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Can not modify domain specific upper limit for FixedMaxQuotaManager");
+ }
+
+ @Override
public Optional<QuotaSize> getDefaultMaxStorage() {
return maxStorage;
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoMaxQuotaManager.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoMaxQuotaManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoMaxQuotaManager.java
index 9e06bc3..f30b86b 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoMaxQuotaManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoMaxQuotaManager.java
@@ -59,6 +59,26 @@ public class NoMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public void setDomainMaxMessage(String domain, QuotaCount count) throws MailboxException {
+ throw new MailboxException("Operation is not supported");
+ }
+
+ @Override
+ public void setDomainMaxStorage(String domain, QuotaSize size) throws MailboxException {
+ throw new MailboxException("Operation is not supported");
+ }
+
+ @Override
+ public void removeDomainMaxMessage(String domain) throws MailboxException {
+ throw new MailboxException("Operation is not supported");
+ }
+
+ @Override
+ public void removeDomainMaxStorage(String domain) throws MailboxException {
+ throw new MailboxException("Operation is not supported");
+ }
+
+ @Override
public void setDefaultMaxStorage(QuotaSize defaultMaxStorage) throws MailboxException {
throw new MailboxException("Operation is not supported");
}
@@ -99,6 +119,16 @@ public class NoMaxQuotaManager implements MaxQuotaManager {
}
@Override
+ public Optional<QuotaCount> getDomainMaxMessage(String domain) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<QuotaSize> getDomainMaxStorage(String domain) {
+ return Optional.empty();
+ }
+
+ @Override
public Optional<QuotaSize> getDefaultMaxStorage() {
return Optional.empty();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mailbox/store/src/test/java/org/apache/james/mailbox/store/quota/GenericMaxQuotaManagerTest.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/quota/GenericMaxQuotaManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/quota/GenericMaxQuotaManagerTest.java
index cef25e2..b2f152c 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/quota/GenericMaxQuotaManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/quota/GenericMaxQuotaManagerTest.java
@@ -27,12 +27,14 @@ import org.apache.james.mailbox.quota.MaxQuotaManager;
import org.apache.james.mailbox.quota.QuotaCount;
import org.apache.james.mailbox.quota.QuotaSize;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public abstract class GenericMaxQuotaManagerTest {
private QuotaRoot quotaRoot;
private MaxQuotaManager maxQuotaManager;
+ private String domain;
protected abstract MaxQuotaManager provideMaxQuotaManager();
@@ -40,6 +42,7 @@ public abstract class GenericMaxQuotaManagerTest {
public void setUp() {
maxQuotaManager = provideMaxQuotaManager();
quotaRoot = QuotaRoot.quotaRoot("benwa");
+ domain = "domain";
}
@Test
@@ -52,6 +55,14 @@ public abstract class GenericMaxQuotaManagerTest {
assertThat(maxQuotaManager.getMaxStorage(quotaRoot)).isEmpty();
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void getMaxMessageShouldReturnDomainWhenNoValue() throws Exception {
+ maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(36));
+ maxQuotaManager.setDomainMaxMessage(domain, QuotaCount.count(23));
+ assertThat(maxQuotaManager.getMaxMessage(quotaRoot)).contains(QuotaCount.count(23));
+ }
+
@Test
public void getMaxMessageShouldReturnDefaultWhenNoValue() throws Exception {
maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(36));
@@ -64,6 +75,14 @@ public abstract class GenericMaxQuotaManagerTest {
assertThat(maxQuotaManager.getMaxStorage(quotaRoot)).contains(QuotaSize.size(36));
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void getMaxStorageShouldReturnDomainWhenNoValue() throws Exception {
+ maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(234));
+ maxQuotaManager.setDomainMaxStorage(domain, QuotaSize.size(111));
+ assertThat(maxQuotaManager.getMaxStorage(quotaRoot)).contains(QuotaSize.size(111));
+ }
+
@Test
public void getMaxMessageShouldReturnProvidedValue() throws Exception {
maxQuotaManager.setMaxMessage(quotaRoot, QuotaCount.count(36));
@@ -122,6 +141,14 @@ public abstract class GenericMaxQuotaManagerTest {
.containsEntry(Quota.Scope.Global, QuotaCount.count(123));
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void listMaxMessagesDetailsShouldReturnDomainValueWhenDefined() throws Exception {
+ maxQuotaManager.setDomainMaxMessage(domain, QuotaCount.count(123));
+ assertThat(maxQuotaManager.listMaxMessagesDetails(quotaRoot))
+ .hasSize(1)
+ .containsEntry(Quota.Scope.Domain, QuotaCount.count(123));
+ }
@Test
public void listMaxMessagesDetailsShouldReturnUserValueWhenDefined() throws Exception {
@@ -132,7 +159,7 @@ public abstract class GenericMaxQuotaManagerTest {
}
@Test
- public void listMaxMessagesDetailsShouldReturnBothValuesWhenDefined() throws Exception {
+ public void listMaxMessagesDetailsShouldReturnBothValuesWhenGlobalAndUserDefined() throws Exception {
maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(1234));
maxQuotaManager.setMaxMessage(quotaRoot, QuotaCount.count(123));
assertThat(maxQuotaManager.listMaxMessagesDetails(quotaRoot))
@@ -141,6 +168,18 @@ public abstract class GenericMaxQuotaManagerTest {
.containsEntry(Quota.Scope.User, QuotaCount.count(123));
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void listMaxMessagesDetailsShouldReturnAllValuesWhenDefined() throws Exception {
+ maxQuotaManager.setDefaultMaxMessage(QuotaCount.count(1234));
+ maxQuotaManager.setDomainMaxMessage(domain, QuotaCount.count(333));
+ maxQuotaManager.setMaxMessage(quotaRoot, QuotaCount.count(123));
+ assertThat(maxQuotaManager.listMaxMessagesDetails(quotaRoot))
+ .hasSize(3)
+ .containsEntry(Quota.Scope.Global, QuotaCount.count(1234))
+ .containsEntry(Quota.Scope.Domain, QuotaCount.count(333))
+ .containsEntry(Quota.Scope.User, QuotaCount.count(123));
+ }
@Test
public void listMaxStorageDetailsShouldReturnGlobalValueWhenDefined() throws Exception {
@@ -150,6 +189,14 @@ public abstract class GenericMaxQuotaManagerTest {
.containsEntry(Quota.Scope.Global, QuotaSize.size(1111));
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void listMaxStorageDetailsShouldReturnDomainValueWhenDefined() throws Exception {
+ maxQuotaManager.setDomainMaxStorage(domain, QuotaSize.size(1111));
+ assertThat(maxQuotaManager.listMaxStorageDetails(quotaRoot))
+ .hasSize(1)
+ .containsEntry(Quota.Scope.Domain, QuotaSize.size(1111));
+ }
@Test
public void listMaxStorageDetailsShouldReturnUserValueWhenDefined() throws Exception {
@@ -169,4 +216,53 @@ public abstract class GenericMaxQuotaManagerTest {
.containsEntry(Quota.Scope.User, QuotaSize.size(4444));
}
+ @Ignore("how can we link domain and quotaRoot ?")
+ @Test
+ public void listMaxStorageDetailsShouldReturnAllValuesWhenDefined() throws Exception {
+ maxQuotaManager.setDefaultMaxStorage(QuotaSize.size(3333));
+ maxQuotaManager.setDomainMaxStorage(domain, QuotaSize.size(2222));
+ maxQuotaManager.setMaxStorage(quotaRoot, QuotaSize.size(4444));
+ assertThat(maxQuotaManager.listMaxStorageDetails(quotaRoot))
+ .hasSize(3)
+ .containsEntry(Quota.Scope.Global, QuotaSize.size(3333))
+ .containsEntry(Quota.Scope.Domain, QuotaSize.size(2222))
+ .containsEntry(Quota.Scope.User, QuotaSize.size(4444));
+ }
+
+ @Test
+ public void getDomainMaxMessageShouldReturnEmptyWhenNoDefaultValue() {
+ assertThat(maxQuotaManager.getDomainMaxMessage(domain)).isEmpty();
+ }
+
+ @Test
+ public void getDomainMaxStorageShouldReturnEmptyWhenNoDefaultValue() {
+ assertThat(maxQuotaManager.getDomainMaxStorage(domain)).isEmpty();
+ }
+
+ @Test
+ public void getDomainMaxMessageShouldReturnProvidedValue() throws Exception {
+ maxQuotaManager.setDomainMaxMessage(domain, QuotaCount.count(36));
+ assertThat(maxQuotaManager.getDomainMaxMessage(domain)).contains(QuotaCount.count(36));
+ }
+
+ @Test
+ public void getDomainMaxStorageShouldReturnProvidedValue() throws Exception {
+ maxQuotaManager.setDomainMaxStorage(domain, QuotaSize.size(36));
+ assertThat(maxQuotaManager.getDomainMaxStorage(domain)).contains(QuotaSize.size(36));
+ }
+
+ @Test
+ public void deleteDomainMaxStorageShouldRemoveCurrentValue() throws Exception {
+ maxQuotaManager.setDomainMaxStorage(domain, QuotaSize.size(36));
+ maxQuotaManager.removeDomainMaxStorage(domain);
+ assertThat(maxQuotaManager.getDomainMaxStorage(domain)).isEmpty();
+ }
+
+ @Test
+ public void deleteDomainMaxMessageShouldRemoveCurrentValue() throws Exception {
+ maxQuotaManager.setDomainMaxMessage(domain, QuotaCount.count(36));
+ maxQuotaManager.removeDomainMaxMessage(domain);
+ assertThat(maxQuotaManager.getDomainMaxMessage(domain)).isEmpty();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
----------------------------------------------------------------------
diff --git a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
index c27c9ca..b19d81e 100644
--- a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
+++ b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
@@ -49,6 +49,7 @@ import org.apache.james.mailbox.cassandra.modules.CassandraSubscriptionModule;
import org.apache.james.mailbox.cassandra.modules.CassandraUidModule;
import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManager;
import org.apache.james.mailbox.cassandra.quota.CassandraDefaultMaxQuotaDao;
+import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
import org.apache.james.mailbox.exception.MailboxException;
@@ -129,6 +130,7 @@ public class CassandraHostSystem extends JamesImapHostSystem {
perUserMaxQuotaManager = new CassandraPerUserMaxQuotaManager(
new CassandraPerUserMaxQuotaDao(session),
+ new CassandraPerDomainMaxQuotaDao(cassandra.getConf()),
new CassandraDefaultMaxQuotaDao(session));
CassandraCurrentQuotaManager currentQuotaManager = new CassandraCurrentQuotaManager(session);
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraQuotaModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraQuotaModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraQuotaModule.java
index 6d3a04b..9ef5286 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraQuotaModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraQuotaModule.java
@@ -22,6 +22,7 @@ package org.apache.james.modules.mailbox;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManager;
import org.apache.james.mailbox.cassandra.quota.CassandraDefaultMaxQuotaDao;
+import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
import org.apache.james.mailbox.quota.CurrentQuotaManager;
@@ -43,6 +44,7 @@ public class CassandraQuotaModule extends AbstractModule {
protected void configure() {
bind(CassandraCurrentQuotaManager.class).in(Scopes.SINGLETON);
bind(CassandraDefaultMaxQuotaDao.class).in(Scopes.SINGLETON);
+ bind(CassandraPerDomainMaxQuotaDao.class).in(Scopes.SINGLETON);
bind(CassandraPerUserMaxQuotaDao.class).in(Scopes.SINGLETON);
bind(CassandraPerUserMaxQuotaManager.class).in(Scopes.SINGLETON);
bind(DefaultUserQuotaRootResolver.class).in(Scopes.SINGLETON);
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
new file mode 100644
index 0000000..f8c0ace
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
@@ -0,0 +1,297 @@
+/****************************************************************
+ * 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 java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
+import org.apache.james.webadmin.utils.JsonExtractException;
+import org.apache.james.webadmin.utils.JsonExtractor;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.james.webadmin.utils.JsonTransformerModule;
+import org.apache.james.webadmin.validation.Quotas;
+import org.eclipse.jetty.http.HttpStatus;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import spark.Request;
+import spark.Service;
+
+@Api(tags = "DomainQuota")
+@Path(DomainQuotaRoutes.QUOTA_ENDPOINT)
+@Produces("application/json")
+public class DomainQuotaRoutes implements Routes {
+
+ private static final String DOMAIN = "domain";
+ static final String QUOTA_ENDPOINT = "/quota/domains/:" + DOMAIN;
+ private static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
+ private static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
+
+ private final DomainList domainList;
+ private final DomainQuotaService domainQuotaService;
+ private final JsonTransformer jsonTransformer;
+ private final JsonExtractor<QuotaDTO> jsonExtractor;
+ private Service service;
+
+ @Inject
+ public DomainQuotaRoutes(DomainList domainList, DomainQuotaService domainQuotaService, JsonTransformer jsonTransformer, Set<JsonTransformerModule> modules) {
+ this.domainList = domainList;
+ this.domainQuotaService = domainQuotaService;
+ this.jsonTransformer = jsonTransformer;
+ this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class, modules.stream().map(JsonTransformerModule::asJacksonModule).collect(Collectors.toList()));
+ }
+
+ @Override
+ public void define(Service service) {
+ this.service = service;
+
+ defineGetQuotaCount();
+ defineDeleteQuotaCount();
+ defineUpdateQuotaCount();
+
+ defineGetQuotaSize();
+ defineDeleteQuotaSize();
+ defineUpdateQuotaSize();
+
+ defineGetQuota();
+ defineUpdateQuota();
+ }
+
+ @PUT
+ @ApiOperation(value = "Updating count and size at the same time")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "org.apache.james.webadmin.dto.QuotaDTO", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer or not unlimited value (-1)."),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuota() {
+ service.put(QUOTA_ENDPOINT, ((request, response) -> {
+ String domain = checkDomainExist(request);
+ QuotaDTO quotaDTO = parseQuotaDTO(request);
+ domainQuotaService.defineQuota(domain, quotaDTO);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ }));
+ }
+
+ @GET
+ @ApiOperation(
+ value = "Reading count and size at the same time",
+ notes = "If there is no limitation for count and/or size, the returned value will be -1"
+ )
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = QuotaDTO.class),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuota() {
+ service.get(QUOTA_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ return domainQuotaService.getQuota(domain);
+ }, jsonTransformer);
+ }
+
+ @DELETE
+ @Path("/size")
+ @ApiOperation(value = "Removing per domain mail size limitation by updating to unlimited value")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The value is updated to unlimited value."),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineDeleteQuotaSize() {
+ service.delete(SIZE_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ domainQuotaService.remoteMaxQuotaSize(domain);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @PUT
+ @Path("/size")
+ @ApiOperation(value = "Updating per domain mail size limitation")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "integer", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer."),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuotaSize() {
+ service.put(SIZE_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ QuotaSize quotaSize = Quotas.quotaSize(request.body());
+ domainQuotaService.setMaxSizeQuota(domain, quotaSize);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @GET
+ @Path("/size")
+ @ApiOperation(value = "Reading per domain mail size limitation")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = Long.class),
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "No value defined"),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuotaSize() {
+ service.get(SIZE_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ Optional<QuotaSize> maxSizeQuota = domainQuotaService.getMaxSizeQuota(domain);
+ if (maxSizeQuota.isPresent()) {
+ return maxSizeQuota;
+ }
+ response.status(HttpStatus.NO_CONTENT_204);
+ return null;
+ }, jsonTransformer);
+ }
+
+ @DELETE
+ @Path("/count")
+ @ApiOperation(value = "Removing per domain mail count limitation by updating to unlimited value")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The value is updated to unlimited value."),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineDeleteQuotaCount() {
+ service.delete(COUNT_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ domainQuotaService.remoteMaxQuotaCount(domain);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @PUT
+ @Path("/count")
+ @ApiOperation(value = "Updating per domain mail count limitation")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "integer", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer."),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuotaCount() {
+ service.put(COUNT_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ QuotaCount quotaCount = Quotas.quotaCount(request.body());
+ domainQuotaService.setMaxCountQuota(domain, quotaCount);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @GET
+ @Path("/count")
+ @ApiOperation(value = "Reading per domain mail count limitation")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = Long.class),
+ @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The requested rdomain can not be found."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuotaCount() {
+ service.get(COUNT_ENDPOINT, (request, response) -> {
+ String domain = checkDomainExist(request);
+ Optional<QuotaCount> maxCountQuota = domainQuotaService.getMaxCountQuota(domain);
+ if (maxCountQuota.isPresent()) {
+ return maxCountQuota;
+ }
+ response.status(HttpStatus.NO_CONTENT_204);
+ return null;
+ }, jsonTransformer);
+ }
+
+ private String checkDomainExist(Request request) {
+ String domain = request.params(DOMAIN);
+ try {
+ if (!domainList.containsDomain(domain)) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.NOT_FOUND_404)
+ .type(ErrorType.NOT_FOUND)
+ .message("Domain not found")
+ .haltError();
+ }
+ } catch (DomainListException e) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.NOT_FOUND_404)
+ .type(ErrorType.NOT_FOUND)
+ .cause(e)
+ .haltError();
+ }
+ return domain;
+ }
+
+ private QuotaDTO parseQuotaDTO(Request request) {
+ try {
+ return jsonExtractor.parse(request.body());
+ } catch (IllegalArgumentException e) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .type(ErrorType.INVALID_ARGUMENT)
+ .message("Quota should be positive or unlimited (-1)")
+ .cause(e)
+ .haltError();
+ } catch (JsonExtractException e) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .type(ErrorType.INVALID_ARGUMENT)
+ .message("Malformed JSON input")
+ .cause(e)
+ .haltError();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaService.java
new file mode 100644
index 0000000..35a10ff
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaService.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.routes;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.webadmin.dto.QuotaDTO;
+
+import com.github.fge.lambdas.Throwing;
+
+public class DomainQuotaService {
+
+ private final MaxQuotaManager maxQuotaManager;
+
+ @Inject
+ public DomainQuotaService(MaxQuotaManager maxQuotaManager) {
+ this.maxQuotaManager = maxQuotaManager;
+ }
+
+ public Optional<QuotaCount> getMaxCountQuota(String domain) {
+ return maxQuotaManager.getDomainMaxMessage(domain);
+ }
+
+ public void setMaxCountQuota(String domain, QuotaCount quotaCount) throws MailboxException {
+ maxQuotaManager.setDomainMaxMessage(domain, quotaCount);
+ }
+
+ public void remoteMaxQuotaCount(String domain) throws MailboxException {
+ maxQuotaManager.removeDomainMaxMessage(domain);
+ }
+
+ public Optional<QuotaSize> getMaxSizeQuota(String domain) {
+ return maxQuotaManager.getDomainMaxStorage(domain);
+ }
+
+ public void setMaxSizeQuota(String domain, QuotaSize quotaSize) throws MailboxException {
+ maxQuotaManager.setDomainMaxStorage(domain, quotaSize);
+ }
+
+ public void remoteMaxQuotaSize(String domain) throws MailboxException {
+ maxQuotaManager.removeDomainMaxStorage(domain);
+ }
+
+ public QuotaDTO getQuota(String domain) {
+ return QuotaDTO
+ .builder()
+ .count(maxQuotaManager.getDomainMaxMessage(domain))
+ .size(maxQuotaManager.getDomainMaxStorage(domain))
+ .build();
+ }
+
+ public void defineQuota(String domain, QuotaDTO quota) {
+ quota.getCount()
+ .ifPresent(Throwing.consumer(count -> maxQuotaManager.setDomainMaxMessage(domain, count)));
+ quota.getSize()
+ .ifPresent(Throwing.consumer(size -> maxQuotaManager.setDomainMaxStorage(domain, size)));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/5191b5fa/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
new file mode 100644
index 0000000..9f9cab7
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
@@ -0,0 +1,430 @@
+/****************************************************************
+ * 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 org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.jackson.QuotaModule;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.path.json.JsonPath;
+
+public class DomainQuotaRoutesTest {
+
+ private static final String QUOTA_DOMAINS = "/quota/domains";
+ private static final String PERDU_COM = "perdu.com";
+ private static final String TROUVÉ_COM = "trouvé.com";
+ private static final String COUNT = "count";
+ private static final String SIZE = "size";
+ private WebAdminServer webAdminServer;
+ private InMemoryPerUserMaxQuotaManager maxQuotaManager;
+
+ @Before
+ public void setUp() throws Exception {
+ maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
+ MemoryDomainList memoryDomainList = new MemoryDomainList(new InMemoryDNSService());
+ memoryDomainList.setAutoDetect(false);
+ memoryDomainList.addDomain(TROUVÉ_COM);
+ MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService());
+ domainList.addDomain(TROUVÉ_COM);
+ DomainQuotaService domainQuotaService = new DomainQuotaService(maxQuotaManager);
+ QuotaModule quotaModule = new QuotaModule();
+ DomainQuotaRoutes domainQuotaRoutes = new DomainQuotaRoutes(domainList, domainQuotaService, new JsonTransformer(quotaModule), ImmutableSet.of(quotaModule));
+ webAdminServer = WebAdminUtils.createWebAdminServer(
+ new NoopMetricFactory(),
+ domainQuotaRoutes);
+ webAdminServer.configure(NO_CONFIGURATION);
+ webAdminServer.await();
+
+ RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
+ .build();
+ RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+ }
+
+ @After
+ public void stop() {
+ webAdminServer.destroy();
+ }
+
+ @Test
+ public void getCountShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .get(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getCountShouldReturnNoContentByDefault() {
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+ }
+
+ @Test
+ public void getCountShouldReturnStoredValue() {
+ int value = 42;
+ maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(value));
+
+ Long actual =
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(actual).isEqualTo(value);
+ }
+
+ @Test
+ public void putCountShouldReturnNotFoundWhenDomainDoesntExist() {
+ given()
+ .body("123")
+ .when()
+ .put(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void putCountShouldRejectInvalid() {
+ Map<String, Object> errors = given()
+ .body("invalid")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .contentType(ContentType.JSON)
+ .extract()
+ .body()
+ .jsonPath()
+ .getMap(".");
+
+ assertThat(errors)
+ .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+ .containsEntry("type", "InvalidArgument")
+ .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
+ .containsEntry("cause", "For input string: \"invalid\"");
+ }
+
+ @Test
+ public void putCountShouldSetToInfiniteWhenMinusOne() {
+ given()
+ .body("-1")
+ .when()
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).contains(QuotaCount.unlimited());
+ }
+
+ @Test
+ public void putCountShouldRejectNegativeOtherThanMinusOne() {
+ Map<String, Object> errors = given()
+ .body("-2")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .contentType(ContentType.JSON)
+ .extract()
+ .body()
+ .jsonPath()
+ .getMap(".");
+
+ assertThat(errors)
+ .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+ .containsEntry("type", "InvalidArgument")
+ .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
+ }
+
+ @Test
+ public void putCountShouldAcceptValidValue() {
+ given()
+ .body("42")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).contains(QuotaCount.count(42));
+ }
+
+ @Test
+ public void deleteCountShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .delete(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void deleteCountShouldSetQuotaToEmpty() {
+ maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(42));
+
+ given()
+ .delete(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).isEmpty();
+ }
+
+ @Test
+ public void getSizeShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .get(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getSizeShouldReturnNoContentByDefault() {
+ when()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+ }
+
+ @Test
+ public void getSizeShouldReturnStoredValue() {
+ long value = 42;
+ maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(value));
+
+
+ long quota =
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(quota).isEqualTo(value);
+ }
+
+ @Test
+ public void putSizeShouldRejectInvalid() {
+ Map<String, Object> errors = given()
+ .body("invalid")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .contentType(ContentType.JSON)
+ .extract()
+ .body()
+ .jsonPath()
+ .getMap(".");
+
+ assertThat(errors)
+ .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+ .containsEntry("type", "InvalidArgument")
+ .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
+ .containsEntry("cause", "For input string: \"invalid\"");
+ }
+
+ @Test
+ public void putSizeShouldReturnNotFoundWhenDomainDoesntExist() {
+ given()
+ .body("123")
+ .when()
+ .put(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void putSizeShouldSetToInfiniteWhenMinusOne() {
+ given()
+ .body("-1")
+ .when()
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).contains(QuotaSize.unlimited());
+ }
+
+ @Test
+ public void putSizeShouldRejectNegativeOtherThanMinusOne() {
+ Map<String, Object> errors = given()
+ .body("-2")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .contentType(ContentType.JSON)
+ .extract()
+ .body()
+ .jsonPath()
+ .getMap(".");
+
+ assertThat(errors)
+ .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+ .containsEntry("type", "InvalidArgument")
+ .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
+ }
+
+ @Test
+ public void putSizeShouldAcceptValidValue() {
+ given()
+ .body("42")
+ .when()
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).contains(QuotaSize.size(42));
+ }
+
+ @Test
+ public void deleteSizeShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .delete(QUOTA_DOMAINS + "/" + PERDU_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void deleteSizeShouldSetQuotaToEmpty() {
+ maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
+
+ given()
+ .delete(QUOTA_DOMAINS + "/" + TROUVÉ_COM + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).isEmpty();
+ }
+
+ @Test
+ public void getQuotaShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .get(QUOTA_DOMAINS + "/" + PERDU_COM)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothEmptyWhenDefaultValues() {
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
+ assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+ }
+
+ @Test
+ public void getQuotaShouldReturnSizeWhenNoCount() {
+ int maxStorage = 42;
+ maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(maxStorage));
+
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getLong(SIZE)).isEqualTo(maxStorage);
+ assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothWhenNoSize() {
+ int maxMessage = 42;
+ maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(maxMessage));
+
+
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
+ assertThat(jsonPath.getLong(COUNT)).isEqualTo(maxMessage);
+ }
+
+ @Test
+ public void putQuotaShouldReturnNotFoundWhenDomainDoesntExist() {
+ when()
+ .put(QUOTA_DOMAINS + "/" + PERDU_COM)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void putQuotaShouldUpdateBothQuota() {
+ given()
+ .body("{\"count\":52,\"size\":42}")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).contains(QuotaCount.count(52));
+ assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).contains(QuotaSize.size(42));
+ }
+
+ @Test
+ public void putQuotaShouldBeAbleToRemoveBothQuota() {
+ given()
+ .body("{\"count\":null,\"count\":null}")
+ .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).isEmpty();
+ assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).isEmpty();
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org