JAMES-2400 Provide a simple scanning implementation for QuotaSearcher
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c58a673c Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c58a673c Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c58a673c Branch: refs/heads/master Commit: c58a673c2ec4b3871ab1f25ad34fd2602ca094d9 Parents: 3bb7ee8 Author: benwa <btell...@linagora.com> Authored: Mon May 21 12:03:31 2018 +0700 Committer: benwa <btell...@linagora.com> Committed: Wed May 23 09:09:41 2018 +0700 ---------------------------------------------------------------------- .../java/org/apache/james/core/CoreFixture.java | 4 +- mailbox/plugin/quota-search-scanning/pom.xml | 102 ++++++++++++++++++ .../quota/search/scanning/ClauseConverter.java | 103 +++++++++++++++++++ .../search/scanning/ScanningQuotaSearcher.java | 74 +++++++++++++ .../MemoryQuotaSearchTestSystemExtension.java | 63 ++++++++++++ .../scanning/ScanningQuotaSearcherTest.java | 28 +++++ mailbox/pom.xml | 1 + pom.xml | 11 ++ 8 files changed, 384 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/core/src/test/java/org/apache/james/core/CoreFixture.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/james/core/CoreFixture.java b/core/src/test/java/org/apache/james/core/CoreFixture.java index 237e78e..4220bc3 100644 --- a/core/src/test/java/org/apache/james/core/CoreFixture.java +++ b/core/src/test/java/org/apache/james/core/CoreFixture.java @@ -20,8 +20,8 @@ package org.apache.james.core; import static org.apache.james.core.CoreFixture.Domains.ALPHABET_TLD; -import static org.apache.james.core.CoreFixture.Domains.SIMPSON_COM; import static org.apache.james.core.CoreFixture.Domains.DOMAIN_TLD; +import static org.apache.james.core.CoreFixture.Domains.SIMPSON_COM; public interface CoreFixture { interface Domains { @@ -34,7 +34,7 @@ public interface CoreFixture { interface Simpson { User BART = User.fromLocalPartWithDomain("bart", SIMPSON_COM); User HOMER = User.fromLocalPartWithDomain("homer", SIMPSON_COM); - User LISA = User.fromLocalPartWithDomain("foo3", SIMPSON_COM); + User LISA = User.fromLocalPartWithDomain("lisa", SIMPSON_COM); } interface Alphabet { http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/plugin/quota-search-scanning/pom.xml ---------------------------------------------------------------------- diff --git a/mailbox/plugin/quota-search-scanning/pom.xml b/mailbox/plugin/quota-search-scanning/pom.xml new file mode 100644 index 0000000..97ad7a9 --- /dev/null +++ b/mailbox/plugin/quota-search-scanning/pom.xml @@ -0,0 +1,102 @@ +<?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"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>apache-james-mailbox</artifactId> + <groupId>org.apache.james</groupId> + <version>3.1.0-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + + <artifactId>apache-james-mailbox-quota-search-scanning</artifactId> + <name>Apache James :: Mailbox :: Plugin :: Quota Search :: Scanning</name> + <description>Apache James Mailbox scanning implementation for quota search</description> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-api</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-memory</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-quota-search</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-quota-search</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-core</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-data-api</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-data-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-launcher</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ClauseConverter.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ClauseConverter.java b/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ClauseConverter.java new file mode 100644 index 0000000..43e158c --- /dev/null +++ b/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ClauseConverter.java @@ -0,0 +1,103 @@ +/**************************************************************** + * 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.quota.search.scanning; + +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +import javax.inject.Inject; + +import org.apache.james.core.User; +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.QuotaCount; +import org.apache.james.mailbox.quota.QuotaManager; +import org.apache.james.mailbox.quota.QuotaSize; +import org.apache.james.mailbox.quota.UserQuotaRootResolver; +import org.apache.james.quota.search.QuotaClause; + +import com.google.common.collect.ImmutableMap; + +public class ClauseConverter { + + private final UserQuotaRootResolver quotaRootResolver; + private final QuotaManager quotaManager; + private final Map<Class<? extends QuotaClause>, Function<QuotaClause, Predicate<User>>> toPredicates; + + @Inject + public ClauseConverter(UserQuotaRootResolver quotaRootResolver, QuotaManager quotaManager) { + this.quotaRootResolver = quotaRootResolver; + this.quotaManager = quotaManager; + this.toPredicates = ImmutableMap.of( + QuotaClause.And.class, this::andToPredicate, + QuotaClause.LessThan.class, this::lessThanToPredicate, + QuotaClause.MoreThan.class, this::moreThanToPredicate, + QuotaClause.HasDomain.class, this::hasDomainToPredicate); + } + + public Predicate<User> andToPredicate(QuotaClause.And and) { + return and.getClauses() + .stream() + .map(this::toPredicate) + .reduce((p1, p2) -> (user -> p1.test(user) && p2.test(user))) + .orElse(user -> true); + } + + public Predicate<User> toPredicate(QuotaClause clause) { + return toPredicates.get(clause.getClass()) + .apply(clause); + } + + public Predicate<User> moreThanToPredicate(QuotaClause clause) { + QuotaClause.MoreThan moreThan = (QuotaClause.MoreThan) clause; + return user -> retrieveUserRatio(user) >= moreThan.getQuotaBoundary().getRatio(); + } + + public Predicate<User> lessThanToPredicate(QuotaClause clause) { + QuotaClause.LessThan lessThan = (QuotaClause.LessThan) clause; + return user -> retrieveUserRatio(user) <= lessThan.getQuotaBoundary().getRatio(); + } + + public Predicate<User> hasDomainToPredicate(QuotaClause clause) { + QuotaClause.HasDomain hasDomain = (QuotaClause.HasDomain) clause; + return user -> user.getDomainPart() + .map(hasDomain.getDomain()::equals) + .orElse(false); + } + + public Predicate<User> andToPredicate(QuotaClause clause) { + QuotaClause.And and = (QuotaClause.And) clause; + return andToPredicate(and); + } + + public double retrieveUserRatio(User user) { + try { + QuotaRoot quotaRoot = quotaRootResolver.forUser(user); + Quota<QuotaSize> storageQuota = quotaManager.getStorageQuota(quotaRoot); + Quota<QuotaCount> messageQuota = quotaManager.getMessageQuota(quotaRoot); + + return Math.max(storageQuota.getRatio(), messageQuota.getRatio()); + } catch (MailboxException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcher.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcher.java b/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcher.java new file mode 100644 index 0000000..8d388d0 --- /dev/null +++ b/mailbox/plugin/quota-search-scanning/src/main/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcher.java @@ -0,0 +1,74 @@ +/**************************************************************** + * 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.quota.search.scanning; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.apache.james.core.User; +import org.apache.james.quota.search.Limit; +import org.apache.james.quota.search.QuotaQuery; +import org.apache.james.quota.search.QuotaSearcher; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.api.UsersRepositoryException; +import org.apache.james.util.streams.Iterators; + +import com.github.steveash.guavate.Guavate; + +public class ScanningQuotaSearcher implements QuotaSearcher { + private final UsersRepository usersRepository; + private final ClauseConverter clauseConverter; + + @Inject + public ScanningQuotaSearcher(UsersRepository usersRepository, ClauseConverter clauseConverter) { + this.usersRepository = usersRepository; + this.clauseConverter = clauseConverter; + } + + @Override + public List<User> search(QuotaQuery query) { + Stream<User> results = Iterators.toStream(listUsers()) + .map(User::fromUsername) + .filter(clauseConverter.andToPredicate(query.getClause())) + .sorted(Comparator.comparing(User::asString)) + .skip(query.getOffset().getValue()); + + return limit(results, query.getLimit()) + .collect(Guavate.toImmutableList()); + } + + public Stream<User> limit(Stream<User> results, Limit limit) { + return limit.getValue() + .map(results::limit) + .orElse(results); + } + + public Iterator<String> listUsers() { + try { + return usersRepository.list(); + } catch (UsersRepositoryException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java new file mode 100644 index 0000000..6bd1df3 --- /dev/null +++ b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java @@ -0,0 +1,63 @@ +/**************************************************************** + * 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.quota.search.scanning; + +import static org.mockito.Mockito.mock; + +import org.apache.james.dnsservice.api.DNSService; +import org.apache.james.domainlist.memory.MemoryDomainList; +import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver; +import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; +import org.apache.james.quota.search.QuotaSearchTestSystem; +import org.apache.james.user.memory.MemoryUsersRepository; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +public class MemoryQuotaSearchTestSystemExtension implements ParameterResolver { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return (parameterContext.getParameter().getType() == QuotaSearchTestSystem.class); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + try { + InMemoryIntegrationResources.Resources resources = new InMemoryIntegrationResources().createResources(new SimpleGroupMembershipResolver()); + + MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(); + + DNSService dnsService = mock(DNSService.class); + MemoryDomainList domainList = new MemoryDomainList(dnsService); + usersRepository.setDomainList(domainList); + + return new QuotaSearchTestSystem( + resources.getMaxQuotaManager(), + resources.getMailboxManager(), + new ScanningQuotaSearcher(usersRepository, + new ClauseConverter(resources.getQuotaRootResolver(), resources.getQuotaManager())), + usersRepository, domainList); + } catch (Exception e) { + throw new ParameterResolutionException("Error while resolving parameter", e); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcherTest.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcherTest.java b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcherTest.java new file mode 100644 index 0000000..bc24047 --- /dev/null +++ b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/ScanningQuotaSearcherTest.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.quota.search.scanning; + +import org.apache.james.quota.search.QuotaSearcherContract; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(MemoryQuotaSearchTestSystemExtension.class) +public class ScanningQuotaSearcherTest implements QuotaSearcherContract { + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/mailbox/pom.xml ---------------------------------------------------------------------- diff --git a/mailbox/pom.xml b/mailbox/pom.xml index beac9a4..4db6033 100644 --- a/mailbox/pom.xml +++ b/mailbox/pom.xml @@ -57,6 +57,7 @@ <module>plugin/quota-mailing-cassandra</module> <module>plugin/quota-mailing-memory</module> <module>plugin/quota-search</module> + <module>plugin/quota-search-scanning</module> <module>plugin/spamassassin</module> </modules> http://git-wip-us.apache.org/repos/asf/james-project/blob/c58a673c/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 3b4fa0b..52e7c40 100644 --- a/pom.xml +++ b/pom.xml @@ -809,6 +809,17 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-quota-search</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-quota-search</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>apache-james-mailbox-scanning-search</artifactId> <version>${project.version}</version> </dependency> --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org