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 2015/06/29 10:23:56 UTC
svn commit: r1688113 - in /james/mailbox/trunk/elasticsearch/src:
main/java/org/apache/james/mailbox/elasticsearch/json/ test/ test/java/
test/java/org/ test/java/org/apache/ test/java/org/apache/james/
test/java/org/apache/james/mailbox/ test/java/org...
Author: btellier
Date: Mon Jun 29 08:23:55 2015
New Revision: 1688113
URL: http://svn.apache.org/r1688113
Log:
MAILBOX-234 Extract specific header values and store it
Added:
james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/EMailer.java
james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
james/mailbox/trunk/elasticsearch/src/test/
james/mailbox/trunk/elasticsearch/src/test/java/
james/mailbox/trunk/elasticsearch/src/test/java/org/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/FieldImpl.java
james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
Added: james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/EMailer.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/EMailer.java?rev=1688113&view=auto
==============================================================================
--- james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/EMailer.java (added)
+++ james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/EMailer.java Mon Jun 29 08:23:55 2015
@@ -0,0 +1,69 @@
+/****************************************************************
+ * 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.elasticsearch.json;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.elasticsearch.common.base.MoreObjects;
+
+import java.util.Objects;
+
+public class EMailer {
+
+ private final String name;
+ private final String address;
+
+ public EMailer(String name, String address) {
+ this.name = name;
+ this.address = address;
+ }
+
+ @JsonProperty(JsonMessageConstants.EMailer.NAME)
+ public String getName() {
+ return name;
+ }
+
+ @JsonProperty(JsonMessageConstants.EMailer.ADDRESS)
+ public String getAddress() {
+ return address;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof EMailer) {
+ EMailer otherEMailer = (EMailer) o;
+ return Objects.equals(name, otherEMailer.name)
+ && Objects.equals(address, otherEMailer.address);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, address);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", name)
+ .add("address", address)
+ .toString();
+ }
+}
Added: james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java?rev=1688113&view=auto
==============================================================================
--- james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java (added)
+++ james/mailbox/trunk/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollection.java Mon Jun 29 08:23:55 2015
@@ -0,0 +1,208 @@
+/****************************************************************
+ * 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.elasticsearch.json;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import org.apache.james.mailbox.store.search.SearchUtil;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.field.address.LenientAddressParser;
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.MimeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class HeaderCollection {
+
+ public static class Builder {
+
+ private final Set<EMailer> toAddressSet;
+ private final Set<EMailer> fromAddressSet;
+ private final Set<EMailer> ccAddressSet;
+ private final Set<EMailer> bccAddressSet;
+ private final Set<String> subjectSet;
+ private final Multimap<String, String> headers;
+ private Optional<ZonedDateTime> sentDate;
+
+ private Builder() {
+ toAddressSet = new HashSet<>();
+ fromAddressSet = new HashSet<>();
+ ccAddressSet = new HashSet<>();
+ bccAddressSet = new HashSet<>();
+ subjectSet = new HashSet<>();
+ headers = ArrayListMultimap.create();
+ sentDate = Optional.empty();
+ }
+
+ public Builder add(Field field) {
+ Preconditions.checkNotNull(field);
+ String headerName = field.getName().toLowerCase();
+ String headerValue = field.getBody();
+ headers.put(headerName, headerValue);
+ handleSpecificHeader(headerName, headerValue);
+ return this;
+ }
+
+ public HeaderCollection build() {
+ return new HeaderCollection(
+ ImmutableSet.copyOf(toAddressSet),
+ ImmutableSet.copyOf(fromAddressSet),
+ ImmutableSet.copyOf(ccAddressSet),
+ ImmutableSet.copyOf(bccAddressSet),
+ ImmutableSet.copyOf(subjectSet),
+ ImmutableMultimap.copyOf(headers),
+ sentDate);
+ }
+
+ private void handleSpecificHeader(String headerName, String headerValue) {
+ switch (headerName) {
+ case TO:
+ case FROM:
+ case CC:
+ case BCC:
+ manageAddressField(headerName, headerValue);
+ break;
+ case SUBJECT:
+ subjectSet.add(headerValue);
+ break;
+ case DATE:
+ sentDate = toISODate(headerValue);
+ break;
+ }
+ }
+
+ private void manageAddressField(String headerName, String headerValue) {
+ LenientAddressParser.DEFAULT
+ .parseAddressList(MimeUtil.unfold(headerValue))
+ .stream()
+ .flatMap(this::convertAddressToMailboxStream)
+ .map((mailbox) -> new EMailer(SearchUtil.getDisplayAddress(mailbox) , mailbox.getAddress()))
+ .collect(Collectors.toCollection(() -> getAddressSet(headerName)));
+ }
+
+ private Stream<Mailbox> convertAddressToMailboxStream(Address address) {
+ if (address instanceof Mailbox) {
+ return Stream.of((Mailbox) address);
+ } else if (address instanceof Group) {
+ return ((Group) address).getMailboxes().stream();
+ }
+ return Stream.empty();
+ }
+
+ private Set<EMailer> getAddressSet(String headerName) {
+ switch (headerName) {
+ case TO:
+ return toAddressSet;
+ case FROM:
+ return fromAddressSet;
+ case CC:
+ return ccAddressSet;
+ case BCC:
+ return bccAddressSet;
+ }
+ throw new RuntimeException(headerName + " is not a address header name");
+ }
+
+ private Optional<ZonedDateTime> toISODate(String value) {
+ try {
+ return Optional.of(ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME));
+ } catch (Exception e) {
+ LOGGER.info("Can not parse receive date " + value);
+ return Optional.empty();
+ }
+ }
+
+ }
+
+ public static final String TO = "to";
+ public static final String FROM = "from";
+ public static final String CC = "cc";
+ public static final String BCC = "bcc";
+ public static final String SUBJECT = "subject";
+ public static final String DATE = "date";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HeaderCollection.class);
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private final ImmutableSet<EMailer> toAddressSet;
+ private final ImmutableSet<EMailer> fromAddressSet;
+ private final ImmutableSet<EMailer> ccAddressSet;
+ private final ImmutableSet<EMailer> bccAddressSet;
+ private final ImmutableSet<String> subjectSet;
+ private final ImmutableMultimap<String, String> headers;
+ private Optional<ZonedDateTime> sentDate;
+
+ private HeaderCollection(ImmutableSet<EMailer> toAddressSet, ImmutableSet<EMailer> fromAddressSet,
+ ImmutableSet<EMailer> ccAddressSet, ImmutableSet<EMailer> bccAddressSet, ImmutableSet<String> subjectSet,
+ ImmutableMultimap<String, String> headers, Optional<ZonedDateTime> sentDate) {
+ this.toAddressSet = toAddressSet;
+ this.fromAddressSet = fromAddressSet;
+ this.ccAddressSet = ccAddressSet;
+ this.bccAddressSet = bccAddressSet;
+ this.subjectSet = subjectSet;
+ this.headers = headers;
+ this.sentDate = sentDate;
+ }
+
+ public Set<EMailer> getToAddressSet() {
+ return toAddressSet;
+ }
+
+ public Set<EMailer> getFromAddressSet() {
+ return fromAddressSet;
+ }
+
+ public Set<EMailer> getCcAddressSet() {
+ return ccAddressSet;
+ }
+
+ public Set<EMailer> getBccAddressSet() {
+ return bccAddressSet;
+ }
+
+ public Set<String> getSubjectSet() {
+ return subjectSet;
+ }
+
+ public Optional<ZonedDateTime> getSentDate() {
+ return sentDate;
+ }
+
+ public Multimap<String, String> getHeaders() {
+ return headers;
+ }
+
+}
Added: james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/FieldImpl.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/FieldImpl.java?rev=1688113&view=auto
==============================================================================
--- james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/FieldImpl.java (added)
+++ james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/FieldImpl.java Mon Jun 29 08:23:55 2015
@@ -0,0 +1,62 @@
+/****************************************************************
+ * 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.elasticsearch.json;
+
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.ByteSequence;
+
+import java.util.Objects;
+
+public class FieldImpl implements Field {
+ private final String name;
+ private final String body;
+
+ public FieldImpl(String name, String body) {
+ this.name = name;
+ this.body = body;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public ByteSequence getRaw() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, body);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof FieldImpl) {
+ FieldImpl otherField = (FieldImpl) o;
+ return Objects.equals(name, otherField.name)
+ && Objects.equals(body, otherField.body);
+ }
+ return false;
+ }
+}
Added: james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java?rev=1688113&view=auto
==============================================================================
--- james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java (added)
+++ james/mailbox/trunk/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/HeaderCollectionTest.java Mon Jun 29 08:23:55 2015
@@ -0,0 +1,151 @@
+/****************************************************************
+ * 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.elasticsearch.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.format.DateTimeFormatter;
+
+import org.junit.Test;
+
+public class HeaderCollectionTest {
+
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
+
+ @Test
+ public void simpleValueAddressHeaderShouldBeAddedToTheAddressSet() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("To", "btellier@linagora.com")).build();
+ assertThat(headerCollection.getToAddressSet())
+ .containsOnly(new EMailer("btellier@linagora.com", "btellier@linagora.com"));
+ }
+
+ @Test
+ public void comaSeparatedAddressShouldBeBothAddedToTheAddressSet() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("To", "btellier@linagora.com, benwa@minet.net")).build();
+ assertThat(headerCollection.getToAddressSet())
+ .containsOnly(
+ new EMailer("btellier@linagora.com", "btellier@linagora.com"),
+ new EMailer("benwa@minet.net", "benwa@minet.net"));
+ }
+
+ @Test
+ public void addressesOfTwoFieldsHavingTheSameNameShouldBeMerged() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("To", "btellier@linagora.com")).add(new FieldImpl("To", "btellier@linagora.com, benwa@minet.net")).build();
+ assertThat(headerCollection.getToAddressSet())
+ .containsOnly(
+ new EMailer("btellier@linagora.com", "btellier@linagora.com"),
+ new EMailer("benwa@minet.net", "benwa@minet.net"));
+ }
+
+ @Test
+ public void displayNamesShouldBeRetreived() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("To", "Christophe Hamerling <ch...@linagora.com>")).build();
+ assertThat(headerCollection.getToAddressSet())
+ .containsOnly(new EMailer("Christophe Hamerling", "chamerling@linagora.com"));
+ }
+
+ @Test
+ public void addressWithTwoDisplayNamesOnTheSameFieldShouldBeRetreived() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("From", "Christophe Hamerling <ch...@linagora.com>, Graham CROSMARIE <gc...@linagora.com>")).build();
+ assertThat(headerCollection.getFromAddressSet())
+ .containsOnly(new EMailer("Christophe Hamerling", "chamerling@linagora.com"),
+ new EMailer("Graham CROSMARIE", "gcrosmarie@linagora.com"));
+
+ }
+
+ @Test
+ public void mixingAddressWithDisplayNamesWithOthersShouldBeAllowed() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("To", "Christophe Hamerling <ch...@linagora.com>, gcrosmarie@linagora.com")).build();
+ assertThat(headerCollection.getToAddressSet())
+ .containsOnly(new EMailer("Christophe Hamerling", "chamerling@linagora.com"),
+ new EMailer("gcrosmarie@linagora.com", "gcrosmarie@linagora.com"));
+ }
+
+ @Test
+ public void displayNamesShouldBeRetreivedOnCc() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Cc", "Christophe Hamerling <ch...@linagora.com>")).build();
+ assertThat(headerCollection.getCcAddressSet())
+ .containsOnly(new EMailer("Christophe Hamerling", "chamerling@linagora.com"));
+ }
+
+ @Test
+ public void displayNamesShouldBeRetreivedOnBcc() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Bcc", "Christophe Hamerling <ch...@linagora.com>")).build();
+ assertThat(headerCollection.getBccAddressSet())
+ .containsOnly(new EMailer("Christophe Hamerling", "chamerling@linagora.com"));
+ }
+
+ @Test
+ public void headerContaingNoAddressShouldBeConsideredBothAsNameAndAddress() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Bcc", "Not an address")).build();
+ assertThat(headerCollection.getBccAddressSet())
+ .containsOnly(new EMailer("Not an address", "Not an address"));
+ }
+
+ @Test
+ public void unclosedAddressSubpartShouldBeWellHandled() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Bcc", "Mickey <tricky@mouse.com")).build();
+ assertThat(headerCollection.getBccAddressSet())
+ .containsOnly(new EMailer("Mickey", "tricky@mouse.com"));
+ }
+
+ @Test
+ public void notComaSeparatedAddressSubpartShouldBeWellHandled() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Bcc", "Mickey <tr...@mouse.com> Miny<he...@polo.com>")).build();
+ assertThat(headerCollection.getBccAddressSet())
+ .containsOnly(new EMailer("Mickey", "tricky@mouse.com"),
+ new EMailer("Miny", "hello@polo.com"));
+ }
+
+ @Test
+ public void notSeparatedAddressSubpartShouldBeWellHandled1() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Bcc", "Mickey <tr...@polo.com>")).build();
+ assertThat(headerCollection.getBccAddressSet())
+ .containsOnly(new EMailer("Mickey", "tricky@mouse.com"),
+ new EMailer("Miny", "hello@polo.com"));
+ }
+
+ @Test
+ public void dateShouldBeRetreived() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Date", "Thu, 4 Jun 2015 06:08:41 +0200")).build();
+ assertThat(DATE_TIME_FORMATTER.format(headerCollection.getSentDate().get()))
+ .isEqualTo("2015/06/04 06:08:41");
+ }
+
+ @Test
+ public void dateShouldBeAbsentOnInvalidHeader() {
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Date", "Not a date")).build();
+ assertThat(headerCollection.getSentDate().isPresent())
+ .isFalse();
+ }
+
+ @Test
+ public void subjectsShouldBeWellRetrieved() {
+ String subject = "A fantastic ElasticSearch module will be available soon for JAMES";
+ HeaderCollection headerCollection = HeaderCollection.builder().add(new FieldImpl("Subject", subject)).build();
+ assertThat(headerCollection.getSubjectSet()).containsOnly("A fantastic ElasticSearch module will be available soon for JAMES");
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void nullFieldShouldThrow() {
+ HeaderCollection.builder().add(null).build();
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org