You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ad...@apache.org on 2018/08/28 12:12:27 UTC
[10/13] james-project git commit: JAMES-2530 Implement JMAP methods
for implementing filtering
JAMES-2530 Implement JMAP methods for implementing filtering
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3bc2eecf
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3bc2eecf
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3bc2eecf
Branch: refs/heads/master
Commit: 3bc2eecf16108c3f4a6c29726d755d2b164b4fd0
Parents: 2224a02
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Aug 28 10:17:21 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue Aug 28 14:11:51 2018 +0200
----------------------------------------------------------------------
.../james/jmap/methods/GetFilterMethod.java | 118 ++++++++++
.../james/jmap/methods/SetFilterMethod.java | 216 +++++++++++++++++++
2 files changed, 334 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/3bc2eecf/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetFilterMethod.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetFilterMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetFilterMethod.java
new file mode 100644
index 0000000..5c04c60
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetFilterMethod.java
@@ -0,0 +1,118 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.methods;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.User;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.Rule;
+import org.apache.james.jmap.model.ClientId;
+import org.apache.james.jmap.model.GetFilterRequest;
+import org.apache.james.jmap.model.GetFilterResponse;
+import org.apache.james.jmap.model.SetError;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.util.MDCBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class GetFilterMethod implements Method {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GetFilterMethod.class);
+
+ private static final Method.Request.Name METHOD_NAME = Method.Request.name("getFilter");
+ private static final Method.Response.Name RESPONSE_NAME = Method.Response.name("filter");
+
+ private final MetricFactory metricFactory;
+ private final FilteringManagement filteringManagement;
+
+ @Inject
+ private GetFilterMethod(MetricFactory metricFactory, FilteringManagement filteringManagement) {
+ this.metricFactory = metricFactory;
+ this.filteringManagement = filteringManagement;
+ }
+
+ @Override
+ public Request.Name requestHandled() {
+ return METHOD_NAME;
+ }
+
+ @Override
+ public Class<? extends JmapRequest> requestType() {
+ return GetFilterRequest.class;
+ }
+
+ @Override
+ public Stream<JmapResponse> process(JmapRequest request, ClientId clientId, MailboxSession mailboxSession) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(clientId);
+ Preconditions.checkNotNull(mailboxSession);
+ Preconditions.checkArgument(request instanceof GetFilterRequest);
+
+ GetFilterRequest filterRequest = (GetFilterRequest) request;
+
+ return metricFactory.withMetric(JMAP_PREFIX + METHOD_NAME.getName(),
+ MDCBuilder.create()
+ .addContext(MDCBuilder.ACTION, "GET_FILTER")
+ .wrapArround(() -> process(clientId, mailboxSession, filterRequest)));
+ }
+
+ private Stream<JmapResponse> process(ClientId clientId, MailboxSession mailboxSession, GetFilterRequest request) {
+ try {
+ User user = User.fromUsername(mailboxSession.getUser().getUserName());
+
+ return retrieveFilter(clientId, user);
+ } catch (Exception e) {
+ LOGGER.warn("Failed to retrieve filter");
+
+ return Stream.of(unKnownError(clientId));
+ }
+ }
+
+ private Stream<JmapResponse> retrieveFilter(ClientId clientId, User user) {
+ List<Rule> rules = filteringManagement.listRulesForUser(user);
+
+ GetFilterResponse getFilterResponse = GetFilterResponse.builder()
+ .rules(rules)
+ .build();
+
+ return Stream.of(JmapResponse.builder()
+ .clientId(clientId)
+ .response(getFilterResponse)
+ .responseName(RESPONSE_NAME)
+ .build());
+ }
+
+ private JmapResponse unKnownError(ClientId clientId) {
+ return JmapResponse.builder()
+ .clientId(clientId)
+ .responseName(RESPONSE_NAME)
+ .response(ErrorResponse.builder()
+ .type(SetError.Type.ERROR.asString())
+ .description("Failed to retrieve filter")
+ .build())
+ .build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/3bc2eecf/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetFilterMethod.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetFilterMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetFilterMethod.java
new file mode 100644
index 0000000..b9eb9e7
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetFilterMethod.java
@@ -0,0 +1,216 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.methods;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.User;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.Rule;
+import org.apache.james.jmap.model.ClientId;
+import org.apache.james.jmap.model.JmapRuleDTO;
+import org.apache.james.jmap.model.SetError;
+import org.apache.james.jmap.model.SetFilterRequest;
+import org.apache.james.jmap.model.SetFilterResponse;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.util.MDCBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+
+public class SetFilterMethod implements Method {
+
+ public static class DuplicatedRuleException extends Exception {
+ private final ImmutableList<Rule.Id> duplicatedIds;
+
+ public DuplicatedRuleException(ImmutableList<Rule.Id> duplicatedIds) {
+ super("The following rules were duplicated:" + format(duplicatedIds));
+ this.duplicatedIds = duplicatedIds;
+ }
+ }
+
+ public static class MultipleMailboxIdException extends Exception {
+ private final ImmutableList<Rule.Id> idsWithMultipleMailboxes;
+
+ public MultipleMailboxIdException(ImmutableList<Rule.Id> idsWithMultipleMailboxes) {
+ super("The following rules were targeting several mailboxes:" + format(idsWithMultipleMailboxes));
+ this.idsWithMultipleMailboxes = idsWithMultipleMailboxes;
+ }
+ }
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SetFilterMethod.class);
+
+ private static final Request.Name METHOD_NAME = Request.name("setFilter");
+ private static final Response.Name RESPONSE_NAME = Response.name("filterSet");
+
+ private static String format(ImmutableList<Rule.Id> ids) {
+ return "[" + ids.stream()
+ .map(Rule.Id::asString)
+ .map(SetFilterMethod::quote)
+ .collect(Collectors.joining(","))
+ + "]";
+ }
+
+ private static String quote(String s) {
+ return "'" + s + "'";
+ }
+
+ private final MetricFactory metricFactory;
+ private final FilteringManagement filteringManagement;
+
+ @Inject
+ public SetFilterMethod(MetricFactory metricFactory, FilteringManagement filteringManagement) {
+ this.filteringManagement = filteringManagement;
+ this.metricFactory = metricFactory;
+ }
+
+ @Override
+ public Request.Name requestHandled() {
+ return METHOD_NAME;
+ }
+
+ @Override
+ public Class<? extends JmapRequest> requestType() {
+ return SetFilterRequest.class;
+ }
+
+ @Override
+ public Stream<JmapResponse> process(JmapRequest request, ClientId clientId, MailboxSession mailboxSession) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(clientId);
+ Preconditions.checkNotNull(mailboxSession);
+
+ Preconditions.checkArgument(request instanceof SetFilterRequest);
+
+ SetFilterRequest setFilterRequest = (SetFilterRequest) request;
+
+ return metricFactory.withMetric(JMAP_PREFIX + METHOD_NAME.getName(),
+ MDCBuilder.create()
+ .addContext(MDCBuilder.ACTION, "SET_FILTER")
+ .addContext("update", setFilterRequest.getSingleton())
+ .wrapArround(
+ () -> process(clientId, mailboxSession, setFilterRequest)));
+ }
+
+ private Stream<JmapResponse> process(ClientId clientId, MailboxSession mailboxSession, SetFilterRequest request) {
+ try {
+ User user = User.fromUsername(mailboxSession.getUser().getUserName());
+
+ return updateFilter(clientId, request, user);
+ } catch (MultipleMailboxIdException e) {
+ LOGGER.debug("Rule targeting several mailboxes", e);
+ return Stream.of(multipleMailboxesError(clientId, e));
+ } catch (DuplicatedRuleException e) {
+ LOGGER.debug("Duplicated rules", e);
+ return Stream.of(duplicatedIdsError(clientId, e));
+ } catch (Exception e) {
+ LOGGER.warn("Failed setting Rules", e);
+ return Stream.of(unKnownError(clientId));
+ }
+ }
+
+ private Stream<JmapResponse> updateFilter(ClientId clientId, SetFilterRequest request, User user) throws DuplicatedRuleException, MultipleMailboxIdException {
+ ImmutableList<Rule> rules = request.getSingleton().stream()
+ .map(JmapRuleDTO::toRule)
+ .collect(ImmutableList.toImmutableList());
+
+ ensureNoDuplicatedRules(rules);
+ ensureNoMultipleMailboxesRules(rules);
+
+ filteringManagement.defineRulesForUser(user, rules);
+
+ return Stream.of(JmapResponse.builder()
+ .clientId(clientId)
+ .responseName(RESPONSE_NAME)
+ .response(SetFilterResponse.updated())
+ .build());
+ }
+
+ private void ensureNoMultipleMailboxesRules(ImmutableList<Rule> rules) throws MultipleMailboxIdException {
+ ImmutableList<Rule.Id> idWithMultipleMailboxes = rules.stream()
+ .filter(rule -> rule.getAction().getAppendInMailboxes().getMailboxIds().size() > 1)
+ .map(Rule::getId)
+ .collect(ImmutableList.toImmutableList());
+
+ if (!idWithMultipleMailboxes.isEmpty()) {
+ throw new MultipleMailboxIdException(idWithMultipleMailboxes);
+ }
+ }
+
+ private void ensureNoDuplicatedRules(List<Rule> rules) throws DuplicatedRuleException {
+ ImmutableList<Rule.Id> duplicatedIds = rules.stream()
+ .collect(ImmutableListMultimap.toImmutableListMultimap(
+ Rule::getId,
+ Function.identity()))
+ .asMap()
+ .entrySet()
+ .stream()
+ .filter(entry -> entry.getValue().size() > 1)
+ .map(Map.Entry::getKey)
+ .collect(ImmutableList.toImmutableList());
+
+ if (!duplicatedIds.isEmpty()) {
+ throw new DuplicatedRuleException(duplicatedIds);
+ }
+ }
+
+ private JmapResponse unKnownError(ClientId clientId) {
+ return JmapResponse.builder()
+ .clientId(clientId)
+ .responseName(RESPONSE_NAME)
+ .response(ErrorResponse.builder()
+ .type(SetError.Type.ERROR.asString())
+ .description("Failed to retrieve filter")
+ .build())
+ .build();
+ }
+
+ private JmapResponse duplicatedIdsError(ClientId clientId, DuplicatedRuleException e) {
+ return JmapResponse.builder()
+ .clientId(clientId)
+ .responseName(RESPONSE_NAME)
+ .response(SetFilterResponse.notUpdated(SetError.builder()
+ .type(SetError.Type.INVALID_ARGUMENTS)
+ .description("The following rules were duplicated: " + format(e.duplicatedIds))
+ .build()))
+ .build();
+ }
+
+ private JmapResponse multipleMailboxesError(ClientId clientId, MultipleMailboxIdException e) {
+ return JmapResponse.builder()
+ .clientId(clientId)
+ .responseName(RESPONSE_NAME)
+ .response(SetFilterResponse.notUpdated(SetError.builder()
+ .type(SetError.Type.INVALID_ARGUMENTS)
+ .description("The following rules targeted several mailboxes, which is not supported: " + format(e.idsWithMultipleMailboxes))
+ .build()))
+ .build();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org