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/30 13:15:58 UTC
[16/26] james-project git commit: JAMES-2529 Extract ContentMatcher
and HeaderExtractor from MailMatcher
JAMES-2529 Extract ContentMatcher and HeaderExtractor from MailMatcher
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7527daec
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7527daec
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7527daec
Branch: refs/heads/master
Commit: 7527daec794b8e0022161e079e9a2bf710c58e77
Parents: aee5424
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Aug 30 15:02:55 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Thu Aug 30 15:07:03 2018 +0200
----------------------------------------------------------------------
.../jmap/mailet/filter/ContentMatcher.java | 118 +++++++++++++++
.../jmap/mailet/filter/HeaderExtractor.java | 93 ++++++++++++
.../james/jmap/mailet/filter/MailMatcher.java | 150 -------------------
3 files changed, 211 insertions(+), 150 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/7527daec/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.java
new file mode 100644
index 0000000..a388332
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/ContentMatcher.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.mailet.filter;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.james.jmap.api.filtering.Rule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+public interface ContentMatcher {
+
+ class AddressHeader {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AddressHeader.class);
+
+ private final Optional<String> personal;
+ private final Optional<String> address;
+ private final String fullAddress;
+
+ private AddressHeader(String fullAddress) {
+ this.fullAddress = fullAddress;
+ Optional<InternetAddress> internetAddress = parseFullAddress();
+ this.personal = internetAddress.map(InternetAddress::getPersonal);
+ this.address = internetAddress.map(InternetAddress::getAddress);
+ }
+
+ private Optional<InternetAddress> parseFullAddress() {
+ try {
+ return Optional.of(new InternetAddress(fullAddress));
+ } catch (AddressException e) {
+ LOGGER.error("error while parsing full address {}", fullAddress, e);
+ return Optional.empty();
+ }
+ }
+ }
+
+ ContentMatcher STRING_CONTAINS_MATCHER = (contents, valueToMatch) -> contents.anyMatch(content -> StringUtils.contains(content, valueToMatch));
+ ContentMatcher STRING_NOT_CONTAINS_MATCHER = negate(STRING_CONTAINS_MATCHER);
+ ContentMatcher STRING_EXACTLY_EQUALS_MATCHER = (contents, valueToMatch) -> contents.anyMatch(content -> StringUtils.equals(content, valueToMatch));
+ ContentMatcher STRING_NOT_EXACTLY_EQUALS_MATCHER = negate(STRING_EXACTLY_EQUALS_MATCHER);
+
+ ContentMatcher ADDRESS_CONTAINS_MATCHER = (contents, valueToMatch) -> contents
+ .map(ContentMatcher::asAddressHeader)
+ .anyMatch(addressHeader -> StringUtils.containsIgnoreCase(addressHeader.fullAddress, valueToMatch));
+ ContentMatcher ADDRESS_NOT_CONTAINS_MATCHER = negate(ADDRESS_CONTAINS_MATCHER);
+ ContentMatcher ADDRESS_EXACTLY_EQUALS_MATCHER = (contents, valueToMatch) -> contents
+ .map(ContentMatcher::asAddressHeader)
+ .anyMatch(addressHeader ->
+ valueToMatch.equalsIgnoreCase(addressHeader.fullAddress)
+ || addressHeader.address.map(valueToMatch::equalsIgnoreCase).orElse(false)
+ || addressHeader.personal.map(valueToMatch::equalsIgnoreCase).orElse(false));
+ ContentMatcher ADDRESS_NOT_EXACTLY_EQUALS_MATCHER = negate(ADDRESS_EXACTLY_EQUALS_MATCHER);
+
+ Map<Rule.Condition.Comparator, ContentMatcher> HEADER_ADDRESS_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Comparator, ContentMatcher>builder()
+ .put(Rule.Condition.Comparator.CONTAINS, ADDRESS_CONTAINS_MATCHER)
+ .put(Rule.Condition.Comparator.NOT_CONTAINS, ADDRESS_NOT_CONTAINS_MATCHER)
+ .put(Rule.Condition.Comparator.EXACTLY_EQUALS, ADDRESS_EXACTLY_EQUALS_MATCHER)
+ .put(Rule.Condition.Comparator.NOT_EXACTLY_EQUALS, ADDRESS_NOT_EXACTLY_EQUALS_MATCHER)
+ .build();
+
+ Map<Rule.Condition.Comparator, ContentMatcher> CONTENT_STRING_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Comparator, ContentMatcher>builder()
+ .put(Rule.Condition.Comparator.CONTAINS, STRING_CONTAINS_MATCHER)
+ .put(Rule.Condition.Comparator.NOT_CONTAINS, STRING_NOT_CONTAINS_MATCHER)
+ .put(Rule.Condition.Comparator.EXACTLY_EQUALS, STRING_EXACTLY_EQUALS_MATCHER)
+ .put(Rule.Condition.Comparator.NOT_EXACTLY_EQUALS, STRING_NOT_EXACTLY_EQUALS_MATCHER)
+ .build();
+
+ Map<Rule.Condition.Field, Map<Rule.Condition.Comparator, ContentMatcher>> CONTENT_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Field, Map<Rule.Condition.Comparator, ContentMatcher>>builder()
+ .put(Rule.Condition.Field.SUBJECT, CONTENT_STRING_MATCHER_REGISTRY)
+ .put(Rule.Condition.Field.TO, HEADER_ADDRESS_MATCHER_REGISTRY)
+ .put(Rule.Condition.Field.CC, HEADER_ADDRESS_MATCHER_REGISTRY)
+ .put(Rule.Condition.Field.RECIPIENT, HEADER_ADDRESS_MATCHER_REGISTRY)
+ .put(Rule.Condition.Field.FROM, HEADER_ADDRESS_MATCHER_REGISTRY)
+ .build();
+
+ static ContentMatcher negate(ContentMatcher contentMatcher) {
+ return (Stream<String> contents, String valueToMatch) ->
+ !contentMatcher.match(contents, valueToMatch);
+ }
+
+ static Optional<ContentMatcher> asContentMatcher(Rule.Condition.Field field, Rule.Condition.Comparator comparator) {
+ return Optional
+ .ofNullable(CONTENT_MATCHER_REGISTRY.get(field))
+ .map(matcherRegistry -> matcherRegistry.get(comparator));
+ }
+
+ static AddressHeader asAddressHeader(String addressAsString) {
+ return new AddressHeader(addressAsString);
+ }
+
+ boolean match(Stream<String> contents, String valueToMatch);
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/7527daec/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
new file mode 100644
index 0000000..65d1629
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
@@ -0,0 +1,93 @@
+/****************************************************************
+ * 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.mailet.filter;
+
+import static org.apache.mailet.base.RFC2822Headers.FROM;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.mail.Address;
+import javax.mail.Message;
+
+import org.apache.james.javax.AddressHelper;
+import org.apache.james.jmap.api.filtering.Rule;
+import org.apache.james.mime4j.util.MimeUtil;
+import org.apache.james.util.StreamUtils;
+import org.apache.mailet.Mail;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.fge.lambdas.functions.ThrowingFunction;
+import com.google.common.collect.ImmutableMap;
+
+public interface HeaderExtractor extends ThrowingFunction<Mail, Stream<String>> {
+ Logger LOGGER = LoggerFactory.getLogger(HeaderExtractor.class);
+
+ HeaderExtractor SUBJECT_EXTRACTOR = mail ->
+ StreamUtils.ofNullables(mail.getMessage().getSubject());
+ HeaderExtractor CC_EXTRACTOR = recipientExtractor(Message.RecipientType.CC);
+ HeaderExtractor TO_EXTRACTOR = recipientExtractor(Message.RecipientType.TO);
+ HeaderExtractor RECIPIENT_EXTRACTOR = and(TO_EXTRACTOR, CC_EXTRACTOR);
+ HeaderExtractor FROM_EXTRACTOR = addressExtractor(mail -> mail.getMessage().getFrom(), FROM);
+
+ Map<Rule.Condition.Field, HeaderExtractor> HEADER_EXTRACTOR_REGISTRY = ImmutableMap.<Rule.Condition.Field, HeaderExtractor>builder()
+ .put(Rule.Condition.Field.SUBJECT, SUBJECT_EXTRACTOR)
+ .put(Rule.Condition.Field.RECIPIENT, RECIPIENT_EXTRACTOR)
+ .put(Rule.Condition.Field.FROM, FROM_EXTRACTOR)
+ .put(Rule.Condition.Field.CC, CC_EXTRACTOR)
+ .put(Rule.Condition.Field.TO, TO_EXTRACTOR)
+ .build();
+
+ static HeaderExtractor and(HeaderExtractor headerExtractor1, HeaderExtractor headerExtractor2) {
+ return (Mail mail) -> StreamUtils.flatten(headerExtractor1.apply(mail), headerExtractor2.apply(mail));
+ }
+
+ static HeaderExtractor recipientExtractor(Message.RecipientType type) {
+ ThrowingFunction<Mail, Address[]> addressGetter = mail -> mail.getMessage().getRecipients(type);
+ String fallbackHeaderName = type.toString();
+
+ return addressExtractor(addressGetter, fallbackHeaderName);
+ }
+
+ static HeaderExtractor addressExtractor(ThrowingFunction<Mail, Address[]> addressGetter, String fallbackHeaderName) {
+ return mail -> {
+ try {
+ return toContent(addressGetter.apply(mail));
+ } catch (Exception e) {
+ LOGGER.info("Failed parsing header. Falling back to unparsed header value matching", e);
+ return Stream.of(mail.getMessage().getHeader(fallbackHeaderName))
+ .map(MimeUtil::unscrambleHeaderValue);
+ }
+ };
+ }
+
+ static Stream<String> toContent(Address[] addresses) {
+ return Optional.ofNullable(addresses)
+ .map(AddressHelper::asStringStream)
+ .orElse(Stream.empty());
+ }
+
+ static Optional<HeaderExtractor> asHeaderExtractor(Rule.Condition.Field field) {
+ return Optional.ofNullable(
+ HeaderExtractor.HEADER_EXTRACTOR_REGISTRY.get(field));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/7527daec/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
index 031e696..ed5db25 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
@@ -20,169 +20,19 @@
package org.apache.james.jmap.mailet.filter;
import static org.apache.james.jmap.api.filtering.Rule.Condition;
-import static org.apache.mailet.base.RFC2822Headers.FROM;
-import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.mail.Address;
-import javax.mail.Message;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.james.javax.AddressHelper;
import org.apache.james.jmap.api.filtering.Rule;
-import org.apache.james.jmap.api.filtering.Rule.Condition.Field;
-import org.apache.james.mime4j.util.MimeUtil;
-import org.apache.james.util.StreamUtils;
import org.apache.mailet.Mail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.github.fge.lambdas.functions.ThrowingFunction;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
public interface MailMatcher {
- interface HeaderExtractor extends ThrowingFunction<Mail, Stream<String>> {
- Logger LOGGER = LoggerFactory.getLogger(HeaderExtractor.class);
-
- HeaderExtractor SUBJECT_EXTRACTOR = mail ->
- StreamUtils.ofNullables(mail.getMessage().getSubject());
- HeaderExtractor CC_EXTRACTOR = recipientExtractor(Message.RecipientType.CC);
- HeaderExtractor TO_EXTRACTOR = recipientExtractor(Message.RecipientType.TO);
- HeaderExtractor RECIPIENT_EXTRACTOR = and(TO_EXTRACTOR, CC_EXTRACTOR);
- HeaderExtractor FROM_EXTRACTOR = addressExtractor(mail -> mail.getMessage().getFrom(), FROM);
-
- Map<Field, HeaderExtractor> HEADER_EXTRACTOR_REGISTRY = ImmutableMap.<Field, HeaderExtractor>builder()
- .put(Field.SUBJECT, SUBJECT_EXTRACTOR)
- .put(Field.RECIPIENT, RECIPIENT_EXTRACTOR)
- .put(Field.FROM, FROM_EXTRACTOR)
- .put(Field.CC, CC_EXTRACTOR)
- .put(Field.TO, TO_EXTRACTOR)
- .build();
-
- static HeaderExtractor and(HeaderExtractor headerExtractor1, HeaderExtractor headerExtractor2) {
- return (Mail mail) -> StreamUtils.flatten(headerExtractor1.apply(mail), headerExtractor2.apply(mail));
- }
-
- static HeaderExtractor recipientExtractor(Message.RecipientType type) {
- ThrowingFunction<Mail, Address[]> addressGetter = mail -> mail.getMessage().getRecipients(type);
- String fallbackHeaderName = type.toString();
-
- return addressExtractor(addressGetter, fallbackHeaderName);
- }
-
- static HeaderExtractor addressExtractor(ThrowingFunction<Mail, Address[]> addressGetter, String fallbackHeaderName) {
- return mail -> {
- try {
- return toContent(addressGetter.apply(mail));
- } catch (Exception e) {
- LOGGER.info("Failed parsing header. Falling back to unparsed header value matching", e);
- return Stream.of(mail.getMessage().getHeader(fallbackHeaderName))
- .map(MimeUtil::unscrambleHeaderValue);
- }
- };
- }
-
- static Stream<String> toContent(Address[] addresses) {
- return Optional.ofNullable(addresses)
- .map(AddressHelper::asStringStream)
- .orElse(Stream.empty());
- }
-
- static Optional<HeaderExtractor> asHeaderExtractor(Field field) {
- return Optional.ofNullable(
- HeaderExtractor.HEADER_EXTRACTOR_REGISTRY.get(field));
- }
- }
-
- interface ContentMatcher {
-
- class AddressHeader {
- private static final Logger LOGGER = LoggerFactory.getLogger(AddressHeader.class);
-
- private final Optional<String> personal;
- private final Optional<String> address;
- private final String fullAddress;
-
- private AddressHeader(String fullAddress) {
- this.fullAddress = fullAddress;
- Optional<InternetAddress> internetAddress = parseFullAddress();
- this.personal = internetAddress.map(InternetAddress::getPersonal);
- this.address = internetAddress.map(InternetAddress::getAddress);
- }
-
- private Optional<InternetAddress> parseFullAddress() {
- try {
- return Optional.of(new InternetAddress(fullAddress));
- } catch (AddressException e) {
- LOGGER.error("error while parsing full address {}", fullAddress, e);
- return Optional.empty();
- }
- }
- }
-
- ContentMatcher STRING_CONTAINS_MATCHER = (contents, valueToMatch) -> contents.anyMatch(content -> StringUtils.contains(content, valueToMatch));
- ContentMatcher STRING_NOT_CONTAINS_MATCHER = negate(STRING_CONTAINS_MATCHER);
- ContentMatcher STRING_EXACTLY_EQUALS_MATCHER = (contents, valueToMatch) -> contents.anyMatch(content -> StringUtils.equals(content, valueToMatch));
- ContentMatcher STRING_NOT_EXACTLY_EQUALS_MATCHER = negate(STRING_EXACTLY_EQUALS_MATCHER);
-
- ContentMatcher ADDRESS_CONTAINS_MATCHER = (contents, valueToMatch) -> contents
- .map(ContentMatcher::asAddressHeader)
- .anyMatch(addressHeader -> StringUtils.containsIgnoreCase(addressHeader.fullAddress, valueToMatch));
- ContentMatcher ADDRESS_NOT_CONTAINS_MATCHER = negate(ADDRESS_CONTAINS_MATCHER);
- ContentMatcher ADDRESS_EXACTLY_EQUALS_MATCHER = (contents, valueToMatch) -> contents
- .map(ContentMatcher::asAddressHeader)
- .anyMatch(addressHeader ->
- valueToMatch.equalsIgnoreCase(addressHeader.fullAddress)
- || addressHeader.address.map(valueToMatch::equalsIgnoreCase).orElse(false)
- || addressHeader.personal.map(valueToMatch::equalsIgnoreCase).orElse(false));
- ContentMatcher ADDRESS_NOT_EXACTLY_EQUALS_MATCHER = negate(ADDRESS_EXACTLY_EQUALS_MATCHER);
-
- Map<Rule.Condition.Comparator, ContentMatcher> HEADER_ADDRESS_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Comparator, ContentMatcher>builder()
- .put(Condition.Comparator.CONTAINS, ADDRESS_CONTAINS_MATCHER)
- .put(Condition.Comparator.NOT_CONTAINS, ADDRESS_NOT_CONTAINS_MATCHER)
- .put(Condition.Comparator.EXACTLY_EQUALS, ADDRESS_EXACTLY_EQUALS_MATCHER)
- .put(Condition.Comparator.NOT_EXACTLY_EQUALS, ADDRESS_NOT_EXACTLY_EQUALS_MATCHER)
- .build();
-
- Map<Rule.Condition.Comparator, ContentMatcher> CONTENT_STRING_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Comparator, ContentMatcher>builder()
- .put(Condition.Comparator.CONTAINS, STRING_CONTAINS_MATCHER)
- .put(Condition.Comparator.NOT_CONTAINS, STRING_NOT_CONTAINS_MATCHER)
- .put(Condition.Comparator.EXACTLY_EQUALS, STRING_EXACTLY_EQUALS_MATCHER)
- .put(Condition.Comparator.NOT_EXACTLY_EQUALS, STRING_NOT_EXACTLY_EQUALS_MATCHER)
- .build();
-
- Map<Rule.Condition.Field, Map<Rule.Condition.Comparator, ContentMatcher>> CONTENT_MATCHER_REGISTRY = ImmutableMap.<Rule.Condition.Field, Map<Rule.Condition.Comparator, ContentMatcher>>builder()
- .put(Condition.Field.SUBJECT, CONTENT_STRING_MATCHER_REGISTRY)
- .put(Condition.Field.TO, HEADER_ADDRESS_MATCHER_REGISTRY)
- .put(Condition.Field.CC, HEADER_ADDRESS_MATCHER_REGISTRY)
- .put(Condition.Field.RECIPIENT, HEADER_ADDRESS_MATCHER_REGISTRY)
- .put(Condition.Field.FROM, HEADER_ADDRESS_MATCHER_REGISTRY)
- .build();
-
- static ContentMatcher negate(ContentMatcher contentMatcher) {
- return (Stream<String> contents, String valueToMatch) ->
- !contentMatcher.match(contents, valueToMatch);
- }
-
- static Optional<ContentMatcher> asContentMatcher(Condition.Field field, Condition.Comparator comparator) {
- return Optional
- .ofNullable(CONTENT_MATCHER_REGISTRY.get(field))
- .map(matcherRegistry -> matcherRegistry.get(comparator));
- }
-
- static AddressHeader asAddressHeader(String addressAsString) {
- return new AddressHeader(addressAsString);
- }
-
- boolean match(Stream<String> contents, String valueToMatch);
- }
-
class HeaderMatcher implements MailMatcher {
private static final Logger LOGGER = LoggerFactory.getLogger(HeaderMatcher.class);
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org