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 ma...@apache.org on 2018/08/01 12:34:19 UTC

[01/14] james-project git commit: JAMES-2502 remove unused dependencies

Repository: james-project
Updated Branches:
  refs/heads/master 8d22e3568 -> 5935abbb7


JAMES-2502 remove unused dependencies


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8cd1e2cd
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8cd1e2cd
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8cd1e2cd

Branch: refs/heads/master
Commit: 8cd1e2cd75435fbd687cd0ba0ec03ecfe9ccb9cf
Parents: 630dcab
Author: Matthieu Baechler <ma...@apache.org>
Authored: Tue Jul 31 17:07:18 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:20:23 2018 +0200

----------------------------------------------------------------------
 backends-common/cassandra/pom.xml                 | 4 ----
 backends-common/elasticsearch/pom.xml             | 1 +
 backends-common/jpa/pom.xml                       | 5 -----
 mailbox/plugin/quota-search-elasticsearch/pom.xml | 5 +++++
 pom.xml                                           | 5 +++++
 5 files changed, 11 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/8cd1e2cd/backends-common/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/pom.xml b/backends-common/cassandra/pom.xml
index 675bae5..9be80f7 100644
--- a/backends-common/cassandra/pom.xml
+++ b/backends-common/cassandra/pom.xml
@@ -94,10 +94,6 @@
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-text</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/8cd1e2cd/backends-common/elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/pom.xml b/backends-common/elasticsearch/pom.xml
index 02af1ed..b9ae196 100644
--- a/backends-common/elasticsearch/pom.xml
+++ b/backends-common/elasticsearch/pom.xml
@@ -49,6 +49,7 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.assertj</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/8cd1e2cd/backends-common/jpa/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/jpa/pom.xml b/backends-common/jpa/pom.xml
index 81f04fd..da33e18 100644
--- a/backends-common/jpa/pom.xml
+++ b/backends-common/jpa/pom.xml
@@ -38,11 +38,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-jpa_2.0_spec</artifactId>
-            <version>1.1</version>
-        </dependency>
-        <dependency>
             <groupId>org.apache.openjpa</groupId>
             <artifactId>openjpa</artifactId>
             <version>${apache.openjpa.version}</version>

http://git-wip-us.apache.org/repos/asf/james-project/blob/8cd1e2cd/mailbox/plugin/quota-search-elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search-elasticsearch/pom.xml b/mailbox/plugin/quota-search-elasticsearch/pom.xml
index a65bbf8..024d5f3 100644
--- a/mailbox/plugin/quota-search-elasticsearch/pom.xml
+++ b/mailbox/plugin/quota-search-elasticsearch/pom.xml
@@ -112,6 +112,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-migrationsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.junit.platform</groupId>
             <artifactId>junit-platform-launcher</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/8cd1e2cd/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index de9542f..3f87747 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2373,6 +2373,11 @@
             </dependency>
             <dependency>
                 <groupId>org.junit.jupiter</groupId>
+                <artifactId>junit-jupiter-migrationsupport</artifactId>
+                <version>${junit.jupiter.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.junit.jupiter</groupId>
                 <artifactId>junit-jupiter-params</artifactId>
                 <version>${junit.jupiter.version}</version>
             </dependency>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[09/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/PortTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/PortTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/PortTest.java
deleted file mode 100644
index 9d04204..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/PortTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.junit.Test;
-
-public class PortTest {
-    @Test
-    public void assertValidShouldThrowOnNegativePort() {
-        assertThatThrownBy(() -> Port.assertValid(-1))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void assertValidShouldThrowOnZeroPort() {
-        assertThatThrownBy(() -> Port.assertValid(0))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void assertValidShouldAcceptOne() {
-        Port.assertValid(1);
-    }
-
-    @Test
-    public void assertValidShouldAcceptMaxValue() {
-        Port.assertValid(Port.MAX_PORT_VALUE);
-    }
-
-    @Test
-    public void assertValidShouldThrowOnTooBigValue() {
-        assertThatThrownBy(() -> Port.assertValid(Port.MAX_PORT_VALUE + 1))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void isValidShouldReturnFalseWhenNegative() {
-        assertThat(Port.isValid(-1))
-            .isFalse();
-    }
-
-    @Test
-    public void isValidShouldReturnFalseWhenZero() {
-        assertThat(Port.isValid(0))
-            .isFalse();
-    }
-
-    @Test
-    public void isValidShouldReturnTrueWhenOne() {
-        assertThat(Port.isValid(1))
-            .isTrue();
-    }
-
-    @Test
-    public void isValidShouldReturnTrueWhenMaxValue() {
-        assertThat(Port.isValid(Port.MAX_PORT_VALUE))
-            .isTrue();
-    }
-
-    @Test
-    public void isValidShouldReturnFalseWhenAboveMaxValue() {
-        assertThat(Port.isValid(Port.MAX_PORT_VALUE + 1))
-            .isFalse();
-    }
-
-    @Test
-    public void generateValidUnprivilegedPortShouldReturnAValidPort() {
-        assertThat(Port.generateValidUnprivilegedPort())
-            .isBetween(Port.PRIVILEGED_PORT_BOUND, Port.MAX_PORT_VALUE);
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
deleted file mode 100644
index 1b2e86c..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.stream.Stream;
-
-import org.junit.Test;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
-
-import com.github.steveash.guavate.Guavate;
-
-public class StreamUtilsTest {
-
-    @Test
-    public void flattenShouldReturnEmptyWhenEmptyStreams() {
-        assertThat(
-            StreamUtils.<Integer>flatten(ImmutableList.of())
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void flattenShouldPreserveSingleStreams() {
-        assertThat(
-            StreamUtils.flatten(ImmutableList.of(
-                Stream.of(1, 2, 3)))
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void flattenShouldMergeSeveralStreamsTogether() {
-        assertThat(
-            StreamUtils.flatten(ImmutableList.of(
-                Stream.of(1, 2, 3),
-                Stream.of(4, 5)))
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3, 4, 5);
-    }
-
-    @Test
-    public void flattenShouldAcceptEmptyStreams() {
-        assertThat(
-            StreamUtils.flatten(ImmutableList.of(
-                Stream.of()))
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void flattenShouldMergeEmptyStreamsWithOtherData() {
-        assertThat(
-            StreamUtils.flatten(ImmutableList.of(
-                Stream.of(1, 2),
-                Stream.of(),
-                Stream.of(3)))
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void flattenShouldAcceptEmptyVarArg() {
-        assertThat(
-            StreamUtils.flatten()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void flattenShouldThrowOnNullVarArg() {
-        Stream<String>[] streams = null;
-        assertThatThrownBy(() -> StreamUtils.flatten(streams).collect(Guavate.toImmutableList()))
-            .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void flattenShouldFlattenNonEmptyVarArg() {
-        assertThat(StreamUtils.flatten(Stream.of(1), Stream.of(2)).collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2);
-    }
-
-    @Test
-    public void ofNullableShouldReturnEmptyStreamWhenNull() {
-        assertThat(StreamUtils.ofNullable(null)
-            .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void ofNullableShouldReturnAStreamWithElementsOfTheArray() {
-        assertThat(StreamUtils.ofNullable(ImmutableList.of(1, 2).toArray())
-            .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/ValuePatchTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/ValuePatchTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/ValuePatchTest.java
deleted file mode 100644
index ef84393..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/ValuePatchTest.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/****************************************************************
- * 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 modifyTo 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.NoSuchElementException;
-import java.util.Optional;
-
-import org.junit.Test;
-
-public class ValuePatchTest {
-
-    public static final int REPLACEMENT_VALUE = 24;
-    public static final Optional<Integer> REPLACEMENT = Optional.of(REPLACEMENT_VALUE);
-    public static final int VALUE = 12;
-    public static final Optional<Integer> OPTIONAL_OF_VALUE = Optional.of(VALUE);
-
-    @Test
-    public void keepShouldProduceKeptValues() {
-        assertThat(ValuePatch.<Integer>keep().isKept()).isTrue();
-    }
-
-    @Test
-    public void keepShouldThrowOnGet() {
-        assertThatThrownBy(() -> ValuePatch.<Integer>keep().get()).isInstanceOf(NoSuchElementException.class);
-    }
-
-    @Test
-    public void keepShouldNotBeModified() {
-        assertThat(ValuePatch.<Integer>keep().isModified()).isFalse();
-    }
-
-    @Test
-    public void keepShouldNotBeRemoved() {
-        assertThat(ValuePatch.<Integer>keep().isRemoved()).isFalse();
-    }
-
-    @Test
-    public void removeShouldNotBeKept() {
-        assertThat(ValuePatch.<Integer>remove().isKept()).isFalse();
-    }
-
-    @Test
-    public void removeShouldBeRemoved() {
-        assertThat(ValuePatch.<Integer>remove().isRemoved()).isTrue();
-    }
-
-    @Test
-    public void removedShouldNotBeModified() {
-        assertThat(ValuePatch.<Integer>remove().isModified()).isFalse();
-    }
-
-    @Test
-    public void removeShouldThrowOnGet() {
-        assertThatThrownBy(() -> ValuePatch.<Integer>remove().get()).isInstanceOf(NoSuchElementException.class);
-    }
-
-    @Test
-    public void ofNullableShouldBeEquivalentToRemoveWhenNullParameter() {
-        assertThat(ValuePatch.<Integer>ofNullable(null)).isEqualTo(ValuePatch.<Integer>remove());
-    }
-
-    @Test
-    public void ofNullableShouldBeEquivalentToModifyWhenNonNullParameter() {
-        assertThat(ValuePatch.ofNullable(VALUE)).isEqualTo(ValuePatch.modifyTo(VALUE));
-    }
-
-    @Test
-    public void modifyToShouldNotBeKept() {
-        assertThat(ValuePatch.modifyTo(VALUE).isKept()).isFalse();
-    }
-
-    @Test
-    public void modifyToShouldNotBeRemoved() {
-        assertThat(ValuePatch.modifyTo(VALUE).isRemoved()).isFalse();
-    }
-
-    @Test
-    public void modifyToShouldBeModified() {
-        assertThat(ValuePatch.modifyTo(VALUE).isModified()).isTrue();
-    }
-
-    @Test
-    public void modifyToShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> ValuePatch.modifyTo(null)).isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void modifyToShouldBeRetrievedByGet() {
-        assertThat(ValuePatch.modifyTo(VALUE).get()).isEqualTo(VALUE);
-    }
-
-    @Test
-    public void ofOptionalShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> ValuePatch.ofOptional(null)).isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void ofOptionalShouldBeEquivalentToModifyToWhenPresent() {
-        assertThat(ValuePatch.ofOptional(OPTIONAL_OF_VALUE)).isEqualTo(ValuePatch.modifyTo(VALUE));
-    }
-
-    @Test
-    public void ofOptionalShouldBeEquivalentToRemoveWhenEmpty() {
-        assertThat(ValuePatch.ofOptional(Optional.empty())).isEqualTo(ValuePatch.remove());
-    }
-
-    @Test
-    public void notKeptOrElseShouldReturnElseWhenKept() {
-        assertThat(ValuePatch.<Integer>keep().notKeptOrElse(REPLACEMENT)).isEqualTo(REPLACEMENT);
-    }
-
-    @Test
-    public void notKeptOrElseShouldReturnEmptyWhenRemoved() {
-        assertThat(ValuePatch.<Integer>remove().notKeptOrElse(REPLACEMENT)).isEqualTo(Optional.empty());
-    }
-
-    @Test
-    public void notKeptOrElseShouldReturnOptionalWhenModified() {
-        assertThat(ValuePatch.modifyTo(VALUE).notKeptOrElse(REPLACEMENT)).isEqualTo(OPTIONAL_OF_VALUE);
-    }
-
-    @Test
-    public void toOptionalShouldReturnElseWhenKept() {
-        assertThat(ValuePatch.<Integer>keep().toOptional()).isEqualTo(Optional.empty());
-    }
-
-    @Test
-    public void toOptionalShouldReturnEmptyWhenRemoved() {
-        assertThat(ValuePatch.<Integer>remove().toOptional()).isEqualTo(Optional.empty());
-    }
-
-    @Test
-    public void toOptionalShouldReturnOptionalWhenModified() {
-        assertThat(ValuePatch.modifyTo(VALUE).toOptional()).isEqualTo(OPTIONAL_OF_VALUE);
-    }
-
-    @Test
-    public void getOrElseShouldReturnReplacementWhenKept() {
-        assertThat(ValuePatch.<Integer>keep().getOrElse(REPLACEMENT_VALUE)).isEqualTo(REPLACEMENT_VALUE);
-    }
-
-    @Test
-    public void getOrElseShouldReturnReplacementWhenRemoved() {
-        assertThat(ValuePatch.<Integer>remove().getOrElse(REPLACEMENT_VALUE)).isEqualTo(REPLACEMENT_VALUE);
-    }
-
-    @Test
-    public void getOrElseShouldReturnValueWhenPresent() {
-        assertThat(ValuePatch.modifyTo(VALUE).getOrElse(REPLACEMENT_VALUE)).isEqualTo(VALUE);
-    }
-
-    @Test
-    public void getOrElseShouldReturnNullWhenKeptAndNullSpecified() {
-        assertThat(ValuePatch.<Integer>keep().getOrElse(null)).isNull();
-    }
-
-    @Test
-    public void getOrElseShouldReturnNullWhenRemovedAndNullSpecified() {
-        assertThat(ValuePatch.<Integer>remove().getOrElse(null)).isNull();
-    }
-
-    @Test
-    public void getOrElseShouldReturnValueWhenPresentAndNullSpecified() {
-        assertThat(ValuePatch.modifyTo(VALUE).getOrElse(null)).isEqualTo(VALUE);
-    }
-
-    @Test
-    public void mapNotKeptToValueShouldPreserveKept() {
-        assertThat(
-            ValuePatch.<Integer>keep()
-                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
-            .isEmpty();
-    }
-
-    @Test
-    public void mapNotKeptToValueShouldTransformOf() {
-        assertThat(
-            ValuePatch.modifyTo(VALUE)
-                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
-            .contains(VALUE + 1);
-    }
-
-    @Test
-    public void mapNotKeptToValueShouldTransformRemoved() {
-        assertThat(
-            ValuePatch.<Integer>remove()
-                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
-            .contains(REPLACEMENT_VALUE);
-    }
-
-    @Test
-    public void mapNotKeptToValueShouldThrowWhenNull() {
-        assertThatThrownBy(
-            () -> ValuePatch.modifyTo(12)
-                .mapNotKeptToOptional(any -> null)
-                .isPresent())
-            .isInstanceOf(NullPointerException.class);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
deleted file mode 100644
index ec970fb..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/****************************************************************
- * 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.util.date;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.DayOfWeek;
-import java.time.Month;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeParseException;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class ImapDateTimeFormatterTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void dayOfWeekShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getDayOfWeek()).isEqualTo(DayOfWeek.WEDNESDAY);
-    }
-
-    @Test
-    public void parseShouldNotThrowWhenDayOfWeekIsAbsent() {
-        ZonedDateTime.parse("28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenDayOfWeekIsWrong() {
-        expectedException.expect(DateTimeParseException.class);
-        // must be wednesday
-        ZonedDateTime.parse("Mon, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenDayOfWeekIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Abc, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void dayOfWeekShouldBeParsedWhenOneDigit() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getDayOfMonth()).isEqualTo(3);
-    }
-
-    @Test
-    public void dayOfWeekShouldBeParsedWhenTwoDigits() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("13 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getDayOfMonth()).isEqualTo(13);
-    }
-
-    @Test
-    public void parseShouldThrowWhenDayOfMonthIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenDayOfMonthIsNegative() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("-2 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenDayOfMonthIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("64 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void monthOfYearShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getMonth()).isEqualTo(Month.JUNE);
-    }
-
-    @Test
-    public void parseShouldThrowWhenMonthOfYearIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Wed, 28 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenMonthOfYearIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Wed, 28 Abc 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void yearShouldBeParsedWhenFourDigits() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getYear()).isEqualTo(2017);
-    }
-
-    @Test
-    public void yearShouldBeParsedWhenTwoDigitsGreaterThanInitialYear() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("28 Jun 77 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getYear()).isEqualTo(1977);
-    }
-
-    @Test
-    public void yearShouldBeParsedWhenTwoDigitsLesserThanInitialYear() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("28 Jun 64 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getYear()).isEqualTo(2064);
-    }
-
-    @Test
-    public void parseShouldThrowWhenYearIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Wed, 28 Jun 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenYearIsLesserThanTwoDigits() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Wed, 28 Jun 1 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenYearIsGreaterThanFourDigits() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("Wed, 28 Jun 12345 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void hourOfDayShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getHour()).isEqualTo(4);
-    }
-
-    @Test
-    public void parseShouldNotThrowWhenHourOfDayIsLesserThanTwoDigits() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 4:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getHour()).isEqualTo(4);
-    }
-
-    @Test
-    public void parseShouldThrowWhenHourOfDayIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 :35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenHourOfDayIsGreaterThanTwoDigits() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 123:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenHourOfDayIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 48:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void minuteOfHourShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getMinute()).isEqualTo(35);
-    }
-
-    @Test
-    public void parseShouldNotThrowWhenMinuteOfHourIsLesserThanTwoDigits() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:5:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getMinute()).isEqualTo(5);
-    }
-
-    @Test
-    public void parseShouldThrowWhenMinuteOfHourIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04::11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenMinuteOfHourIsGreaterThanTwoDigits() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:123:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenMinuteOfHourDayIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:72:11 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void secondOfMinuteShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getSecond()).isEqualTo(11);
-    }
-
-    @Test
-    public void parseShouldNotThrowWhenSecondOfMinuteIsLesserThanTwoDigits() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:1 -0700", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getSecond()).isEqualTo(1);
-    }
-
-    @Test
-    public void parseShouldNotThrowWhenSecondOfMinuteIsAbsent() {
-        ZonedDateTime.parse("28 Jun 2017 04:35 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenSecondOfMinuteIsGreaterThanTwoDigits() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:35:123 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenSecondOfMinuteDayIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:35:78 -0700", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void offsetShouldBeParsed() {
-        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0712", ImapDateTimeFormatter.rfc5322());
-        assertThat(dateTime.getOffset()).isEqualTo(ZoneOffset.ofHoursMinutes(-7, -12));
-    }
-
-    @Test
-    public void parseShouldThrowWhenOffsetIsAbsent() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:35:11", ImapDateTimeFormatter.rfc5322());
-    }
-
-    @Test
-    public void parseShouldThrowWhenOffsetIsUnknow() {
-        expectedException.expect(DateTimeParseException.class);
-        ZonedDateTime.parse("3 Jun 2017 04:35:11 +7894", ImapDateTimeFormatter.rfc5322());
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
deleted file mode 100644
index deae849..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
+++ /dev/null
@@ -1,514 +0,0 @@
-/****************************************************************
- * 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.util.mime;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
-
-import javax.mail.internet.MimeMessage;
-
-import org.apache.james.mime4j.dom.Message;
-import org.apache.james.mime4j.dom.Multipart;
-import org.apache.james.mime4j.field.Fields;
-import org.apache.james.mime4j.message.BasicBodyFactory;
-import org.apache.james.mime4j.message.BodyPart;
-import org.apache.james.mime4j.message.BodyPartBuilder;
-import org.apache.james.mime4j.message.HeaderImpl;
-import org.apache.james.mime4j.message.MultipartBuilder;
-import org.apache.james.mime4j.stream.Field;
-import org.apache.james.mime4j.util.ByteSequence;
-import org.apache.james.util.mime.MessageContentExtractor.MessageContent;
-import org.junit.Before;
-import org.junit.Test;
-
-public class MessageContentExtractorTest {
-    private static final String BINARY_CONTENT = "binary";
-    private static final String TEXT_CONTENT = "text content";
-    private static final String HTML_CONTENT = "<b>html</b> content";
-    private static final String TEXT_CONTENT2 = "other text content";
-    private static final String HTML_CONTENT2 = "other <b>html</b> content";
-    private static final String ATTACHMENT_CONTENT = "attachment content";
-    private static final String ANY_VALUE = "anyValue";
-    private static final Field CONTENT_ID_FIELD = new Field() {
-        @Override
-        public String getName() {
-            return MessageContentExtractor.CONTENT_ID;
-        }
-
-        @Override
-        public String getBody() {
-            return ANY_VALUE;
-        }
-
-        @Override
-        public ByteSequence getRaw() {
-            return ByteSequence.EMPTY;
-        }
-    };
-
-    private MessageContentExtractor testee;
-
-    private BodyPartBuilder htmlPart;
-    private BodyPartBuilder textPart;
-    private BodyPartBuilder textAttachment;
-    private BodyPartBuilder inlineText;
-    private BodyPartBuilder inlineImage;
-
-    @Before
-    public void setup() throws IOException {
-        testee = new MessageContentExtractor();
-        textPart = BodyPartBuilder.create().setBody(TEXT_CONTENT, "plain", StandardCharsets.UTF_8);
-        htmlPart = BodyPartBuilder.create().setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8);
-        textAttachment = BodyPartBuilder.create()
-                .setBody(ATTACHMENT_CONTENT, "plain", StandardCharsets.UTF_8)
-                .setContentDisposition("attachment");
-        inlineText = BodyPartBuilder.create()
-                .setBody(ATTACHMENT_CONTENT, "plain", StandardCharsets.UTF_8)
-                .setContentDisposition("inline");
-        inlineImage = BodyPartBuilder.create()
-                .setBody(new byte[0], "image/png")
-                .setContentDisposition("inline");
-    }
-
-    @Test
-    public void extractShouldReturnEmptyWhenBinaryContentOnly() throws IOException {
-        Message message = Message.Builder.of()
-                .setBody(BasicBodyFactory.INSTANCE.binaryBody(BINARY_CONTENT, StandardCharsets.UTF_8))
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldReturnTextOnlyWhenTextOnlyBody() throws IOException {
-        Message message = Message.Builder.of()
-                .setBody(TEXT_CONTENT, StandardCharsets.UTF_8)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldReturnHtmlOnlyWhenHtmlOnlyBody() throws IOException {
-        Message message = Message.Builder.of()
-                .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnHtmlAndTextWhenMultipartAlternative() throws IOException {
-        Multipart multipart = MultipartBuilder.create("alternative")
-                .addBodyPart(textPart)
-                .addBodyPart(htmlPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnHtmlWhenMultipartAlternativeWithoutPlainPart() throws IOException {
-        Multipart multipart = MultipartBuilder.create("alternative")
-                .addBodyPart(htmlPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnTextWhenMultipartAlternativeWithoutHtmlPart() throws IOException {
-        Multipart multipart = MultipartBuilder.create("alternative")
-                .addBodyPart(textPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldReturnFirstNonAttachmentPartWhenMultipartMixed() throws IOException {
-        Multipart multipart = MultipartBuilder.create("mixed")
-                .addBodyPart(textAttachment)
-                .addBodyPart(htmlPart)
-                .addBodyPart(textPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-        assertThat(actual.getTextBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldReturnInlinedTextBodyWithoutCIDWhenNoOtherValidParts() throws IOException {
-        String textBody = "body 1";
-        Multipart multipart = MultipartBuilder.create("report")
-            .addBodyPart(BodyPartBuilder.create()
-                .setBody(textBody, "plain", StandardCharsets.UTF_8)
-                .setContentDisposition("inline"))
-            .addBodyPart(BodyPartBuilder.create()
-                .setBody("body 2", "rfc822-headers", StandardCharsets.UTF_8)
-                .setContentDisposition("inline"))
-            .build();
-        Message message = Message.Builder.of()
-            .setBody(multipart)
-            .build();
-
-        MessageContent actual = testee.extract(message);
-
-        assertThat(actual.getTextBody()).contains(textBody);
-    }
-
-    @Test
-    public void extractShouldReturnEmptyWhenMultipartMixedAndFirstPartIsATextAttachment() throws IOException {
-        Multipart multipart = MultipartBuilder.create("mixed")
-                .addBodyPart(textAttachment)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldReturnFirstPartOnlyWhenMultipartMixedAndFirstPartIsHtml() throws IOException {
-        Multipart multipart = MultipartBuilder.create("mixed")
-                .addBodyPart(htmlPart)
-                .addBodyPart(textPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnHtmlAndTextWhenMultipartMixedAndFirstPartIsMultipartAlternative() throws IOException {
-        BodyPart multipartAlternative = BodyPartBuilder.create()
-            .setBody(MultipartBuilder.create("alternative")
-                    .addBodyPart(htmlPart)
-                    .addBodyPart(textPart)
-                    .build())
-            .build();
-        Multipart multipartMixed = MultipartBuilder.create("mixed")
-                .addBodyPart(multipartAlternative)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipartMixed)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnHtmlWhenMultipartRelated() throws IOException {
-        Multipart multipart = MultipartBuilder.create("related")
-                .addBodyPart(htmlPart)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipart)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).isEmpty();
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldReturnHtmlAndTextWhenMultipartAlternativeAndFirstPartIsMultipartRelated() throws IOException {
-        BodyPart multipartRelated = BodyPartBuilder.create()
-            .setBody(MultipartBuilder.create("related")
-                    .addBodyPart(htmlPart)
-                    .build())
-            .build();
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-                .addBodyPart(multipartRelated)
-                .build();
-        Message message = Message.Builder.of()
-                .setBody(multipartAlternative)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldRetrieveHtmlBodyWithOneInlinedHTMLAttachmentWithoutCid() throws IOException {
-        //Given
-        BodyPart inlinedHTMLPart = BodyPartBuilder.create()
-            .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
-            .build();
-        HeaderImpl inlinedHeader = new HeaderImpl();
-        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
-        inlinedHeader.addField(Fields.contentType("text/html; charset=utf-8"));
-        inlinedHTMLPart.setHeader(inlinedHeader);
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-            .addBodyPart(inlinedHTMLPart)
-            .build();
-        Message message = Message.Builder.of()
-            .setBody(multipartAlternative)
-            .build();
-
-        //When
-        MessageContent actual = testee.extract(message);
-
-        //Then
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldNotRetrieveHtmlBodyWithOneInlinedHTMLAttachmentWithCid() throws IOException {
-        //Given
-        BodyPart inlinedHTMLPart = BodyPartBuilder.create()
-            .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
-            .build();
-        HeaderImpl inlinedHeader = new HeaderImpl();
-        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
-        inlinedHeader.addField(Fields.contentType("text/html; charset=utf-8"));
-        inlinedHeader.addField(CONTENT_ID_FIELD);
-        inlinedHTMLPart.setHeader(inlinedHeader);
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-            .addBodyPart(inlinedHTMLPart)
-            .build();
-        Message message = Message.Builder.of()
-            .setBody(multipartAlternative)
-            .build();
-
-        //When
-        MessageContent actual = testee.extract(message);
-
-        //Then
-        assertThat(actual.getHtmlBody()).isEmpty();
-    }
-
-
-    @Test
-    public void extractShouldRetrieveTextBodyWithOneInlinedTextAttachmentWithoutCid() throws IOException {
-        //Given
-        BodyPart inlinedTextPart = BodyPartBuilder.create()
-            .setBody(TEXT_CONTENT, "text", StandardCharsets.UTF_8)
-            .build();
-        HeaderImpl inlinedHeader = new HeaderImpl();
-        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
-        inlinedHeader.addField(Fields.contentType("text/plain; charset=utf-8"));
-        inlinedTextPart.setHeader(inlinedHeader);
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-            .addBodyPart(inlinedTextPart)
-            .build();
-        Message message = Message.Builder.of()
-            .setBody(multipartAlternative)
-            .build();
-
-        //When
-        MessageContent actual = testee.extract(message);
-
-        //Then
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-    }
-
-    @Test
-    public void extractShouldNotRetrieveTextBodyWithOneInlinedTextAttachmentWithCid() throws IOException {
-        //Given
-        BodyPart inlinedTextPart = BodyPartBuilder.create()
-            .setBody(TEXT_CONTENT, "text", StandardCharsets.UTF_8)
-            .build();
-        HeaderImpl inlinedHeader = new HeaderImpl();
-        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
-        inlinedHeader.addField(Fields.contentType("text/plain; charset=utf-8"));
-        inlinedHeader.addField(CONTENT_ID_FIELD);
-        inlinedTextPart.setHeader(inlinedHeader);
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-            .addBodyPart(inlinedTextPart)
-            .build();
-        Message message = Message.Builder.of()
-            .setBody(multipartAlternative)
-            .build();
-
-        //When
-        MessageContent actual = testee.extract(message);
-
-        //Then
-        assertThat(actual.getTextBody()).isEmpty();
-    }
-
-    @Test
-    public void extractShouldRetrieveTextAndHtmlBodyWhenOneInlinedTextAttachmentAndMainContentInMultipart() throws IOException {
-        BodyPart multipartAlternative = BodyPartBuilder.create()
-                .setBody(MultipartBuilder.create("alternative")
-                        .addBodyPart(textPart)
-                        .addBodyPart(htmlPart)
-                        .build())
-                .build();
-
-        Multipart multipartMixed = MultipartBuilder.create("mixed")
-                .addBodyPart(multipartAlternative)
-                .addBodyPart(inlineText)
-                .build();
-
-        Message message = Message.Builder.of()
-                .setBody(multipartMixed)
-                .build();
-
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void extractShouldRetrieveTextBodyAndHtmlBodyWhenTextBodyInMainMultipartAndHtmlBodyInInnerMultipart() throws IOException {
-        BodyPart multipartRelated = BodyPartBuilder.create()
-                .setBody(MultipartBuilder.create("related")
-                        .addBodyPart(htmlPart)
-                        .addBodyPart(inlineImage)
-                        .build())
-                .build();
-
-        Multipart multipartAlternative = MultipartBuilder.create("alternative")
-                .addBodyPart(textPart)
-                .addBodyPart(multipartRelated)
-                .build();
-
-        Message message = Message.Builder.of()
-                .setBody(multipartAlternative)
-                .build();
-
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
-        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnEmptyWhenAllEmpty() {
-        MessageContent messageContent1 = MessageContent.empty();
-        MessageContent messageContent2 = MessageContent.empty();
-        MessageContent expected = MessageContent.empty();
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnFirstWhenSecondEmpty() {
-        MessageContent messageContent1 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
-        MessageContent messageContent2 = MessageContent.empty();
-        MessageContent expected = messageContent1;
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnSecondWhenFirstEmpty() {
-        MessageContent messageContent1 = MessageContent.empty();
-        MessageContent messageContent2 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
-        MessageContent expected = messageContent2;
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnMixWhenFirstTextOnlyAndSecondHtmlOnly() {
-        MessageContent messageContent1 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
-        MessageContent messageContent2 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
-        MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnMixWhenFirstHtmlOnlyAndSecondTextOnly() {
-        MessageContent messageContent1 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
-        MessageContent messageContent2 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
-        MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void mergeMessageContentShouldReturnFirstWhenTwiceAreComplete() {
-        MessageContent messageContent1 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
-        MessageContent messageContent2 = new MessageContent(Optional.of(TEXT_CONTENT2), Optional.of(HTML_CONTENT2));
-        MessageContent expected = messageContent1;
-
-        MessageContent actual = messageContent1.merge(messageContent2);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void extractShouldRespectCharsetWhenOtherThanUTF8() throws IOException {
-        String text = "éééé\r\nèèèè\r\nàààà";
-        Message message = Message.Builder.of()
-                .setBody(text, Charset.forName("windows-1252"))
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(text);
-    }
-
-    @Test
-    public void extractShouldRespectCharsetWhenUTF8() throws IOException {
-        String text = "éééé\r\nèèèè\r\nàààà";
-        Message message = Message.Builder.of()
-                .setBody(text, StandardCharsets.UTF_8)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains(text);
-    }
-
-    @Test
-    public void extractShouldUseUSASCIIWhenNoCharset() throws IOException {
-        String text = "éééé\r\nèèèè\r\nàààà";
-        Message message = Message.Builder.of()
-                .setBody(text, null)
-                .build();
-        MessageContent actual = testee.extract(message);
-        assertThat(actual.getTextBody()).contains("????\r\n????\r\n????");
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
deleted file mode 100644
index 8c9c98b..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.data.MapEntry.entry;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-public class ImmutableCollectorsTest {
-
-    @Test
-    public void immutableListCollectorShouldReturnEmptyImmutableListWhenEmptyStream() {
-        String[] data = {};
-        List<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableList());
-        assertThat(actual).isInstanceOf(ImmutableList.class);
-        assertThat(actual).isEmpty();
-    }
-    
-    @Test
-    public void immutableListCollectorShouldReturnImmutableListWhenOneElementStream() {
-        String[] data = {"a"};
-        List<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableList());
-        assertThat(actual).isInstanceOf(ImmutableList.class);
-        assertThat(actual).containsExactly("a");
-    }
-    
-    @Test
-    public void immutableListCollectorShouldReturnImmutableListWhen3ElementsStream() {
-        String[] data = {"a", "b", "c"};
-        List<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableList());
-        assertThat(actual).isInstanceOf(ImmutableList.class);
-        assertThat(actual).containsExactly("a", "b", "c");
-    }
-
-    @Test
-    public void immutableSetCollectorShouldReturnEmptyImmutableSetWhenEmptyStream() {
-        String[] data = {};
-        Set<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableSet());
-        assertThat(actual).isInstanceOf(ImmutableSet.class);
-        assertThat(actual).isEmpty();
-    }
-
-    @Test
-    public void immutableSetCollectorShouldReturnImmutableSetWhenOneElementStream() {
-        String[] data = {"a"};
-        Set<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableSet());
-        assertThat(actual).isInstanceOf(ImmutableSet.class);
-        assertThat(actual).containsExactly("a");
-    }
-
-    @Test
-    public void immutableSetCollectorShouldReturnImmutableSetWhen3ElementsStream() {
-        String[] data = {"a", "b", "c"};
-        Set<String> actual = Arrays.stream(data)
-            .collect(Guavate.toImmutableSet());
-        assertThat(actual).isInstanceOf(ImmutableSet.class);
-        assertThat(actual).containsExactly("a", "b", "c");
-    }
-
-
-    @Test
-    public void immutableMapCollectorShouldReturnEmptyImmutableMapWhenEmptyStream() {
-        String[] data = {};
-        Map<String, Integer> actual = Arrays.stream(data)
-                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
-        assertThat(actual).isInstanceOf(ImmutableMap.class);
-        assertThat(actual).isEmpty();
-    }
-    
-    @Test
-    public void immutableMapCollectorShouldReturnAppliedImmutableMapWhenOneElementStream() {
-        String[] data = {"a"};
-        Map<String, Integer> actual = Arrays.stream(data)
-                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
-        assertThat(actual).isInstanceOf(ImmutableMap.class);
-        assertThat(actual).containsExactly(entry("A", 1));
-    }
-    
-    @Test
-    public void immutableMapCollectorShouldReturnAppliedImmutableMapWhen3ElementsStream() {
-        String[] data = {"a", "bb", "ccc"};
-        Map<String, Integer> actual = Arrays.stream(data)
-                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
-        assertThat(actual).isInstanceOf(ImmutableMap.class);
-        assertThat(actual).containsExactly(entry("A", 1), entry("BB", 2), entry("CCC", 3));
-    }
-    
-}
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
deleted file mode 100644
index 4c63f1a..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import static java.util.stream.Collectors.toList;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.stream.Stream;
-
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.UnmodifiableIterator;
-
-public class IteratorsTest {
-
-    @Test
-    public void toStreamShouldReturnEmptyStreamWhenEmptyIterator() {
-        //Given
-        UnmodifiableIterator<String> emptyIterator = ImmutableList.<String>of().iterator();
-
-        //When
-        Stream<String> actual = Iterators.toStream(emptyIterator);
-
-        //Then
-        assertThat(actual.count()).isEqualTo(0);
-    }
-
-    @Test
-    public void toStreamShouldReturnSameContent() {
-        //Given
-        UnmodifiableIterator<String> iterator = ImmutableList.of("a", "b", "c").iterator();
-
-        //When
-        Stream<String> actual = Iterators.toStream(iterator);
-
-        //Then
-        assertThat(actual.collect(toList())).containsExactly("a", "b", "c");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
deleted file mode 100644
index 52f1c3a..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.List;
-import java.util.stream.Stream;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-
-public class JamesCollectorsTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void chunkerShouldAcceptEmptyStrem() {
-        Stream<Integer> emptyStream = Stream.of();
-
-        assertThat(emptyStream.collect(JamesCollectors.chunker(10))
-            .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void chunkerShouldThrowOnZeroChunkSize() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        JamesCollectors.chunker(0);
-    }
-
-    @Test
-    public void chunkerShouldThrowOnNegativeChunkSize() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        JamesCollectors.chunker(-1);
-    }
-
-    @Test
-    public void chunkerShouldChunkMonoValueStreams() {
-        Stream<Integer> monoValueStream = Stream.of(1);
-
-        List<List<Integer>> values = monoValueStream.collect(JamesCollectors.chunker(10))
-            .map(ImmutableList::copyOf)
-            .collect(Guavate.toImmutableList());
-        assertThat(values)
-            .isEqualTo(ImmutableList.of(ImmutableList.of(1)));
-    }
-
-    @Test
-    public void chunkerShouldChunkStreamsSmallerThanChunkSize() {
-        Stream<Integer> stream = Stream.of(1, 2);
-
-        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
-            .map(ImmutableList::copyOf)
-            .collect(Guavate.toImmutableList());
-        assertThat(values)
-            .isEqualTo(ImmutableList.of(ImmutableList.of(1, 2)));
-    }
-
-    @Test
-    public void chunkerShouldChunkStreamsAsBigAsChunkSize() {
-        Stream<Integer> stream = Stream.of(1, 2, 3);
-
-        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
-            .map(ImmutableList::copyOf)
-            .collect(Guavate.toImmutableList());
-        assertThat(values)
-            .isEqualTo(ImmutableList.of(ImmutableList.of(1, 2, 3)));
-    }
-
-    @Test
-    public void chunkerShouldChunkStreamsBiggerThanChunkSize() {
-        Stream<Integer> stream = Stream.of(1, 2, 3, 4);
-
-        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
-            .map(ImmutableList::copyOf)
-            .collect(Guavate.toImmutableList());
-        assertThat(values)
-            .isEqualTo(ImmutableList.of(
-                ImmutableList.of(1, 2, 3),
-                ImmutableList.of(4)));
-    }
-
-    @Test
-    public void chunkerShouldChunkInSeveralBuckets() {
-        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7);
-
-        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
-            .map(ImmutableList::copyOf)
-            .collect(Guavate.toImmutableList());
-        assertThat(values)
-            .isEqualTo(ImmutableList.of(
-                ImmutableList.of(1, 2, 3),
-                ImmutableList.of(4, 5, 6),
-                ImmutableList.of(7)));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/streams/LimitTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/LimitTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/LimitTest.java
deleted file mode 100644
index fcd92d8..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/LimitTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.List;
-import java.util.Optional;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class LimitTest {
-
-    private final List<Integer> aList = ImmutableList.of(1, 2, 3, 4, 5, 6);
-
-    @Rule
-    public final ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void unlimitedShouldCreateLimitWithNoLimit() {
-        Limit testee = Limit.unlimited();
-        assertThat(testee.getLimit()).isEqualTo(Optional.empty());
-    }
-
-    @Test
-    public void beanShouldRespectBeanContract() {
-        EqualsVerifier.forClass(Limit.class)
-            .verify();
-    }
-
-    @Test
-    public void unlimitedShouldCreateLimitThatDoesNotAffectStream() {
-
-        Limit testee = Limit.unlimited();
-        assertThat(
-            testee
-                .applyOnStream(aList.stream())
-                .collect(Guavate.toImmutableList())
-        ).isEqualTo(aList);
-    }
-
-    @Test
-    public void limitShouldCreateLimitWithNoLimit() {
-        int expected = 3;
-
-        Limit testee = Limit.limit(expected);
-        assertThat(testee.getLimit())
-            .isEqualTo(Optional.of(expected));
-    }
-
-    @Test
-    public void limitShouldCreateLimitThatCorrectlyTruncateStream() {
-        Limit testee = Limit.limit(3);
-
-        assertThat(testee
-            .applyOnStream(aList.stream())
-            .collect(Guavate.toImmutableList())
-        ).isEqualTo(ImmutableList.of(1, 2, 3));
-    }
-
-    @Test
-    public void limitShouldThrowAnErrorWhenCalledWithZero() {
-        expectedException.expect(IllegalArgumentException.class);
-        Limit.limit(0);
-    }
-
-
-    @Test
-    public void limitShouldThrowAnErrorWhenCalledWithNegativeValue() {
-        expectedException.expect(IllegalArgumentException.class);
-        Limit.limit(-1);
-    }
-
-    @Test
-    public void ofShouldTakePositiveValueAsLimit() {
-        assertThat(Limit.from(3))
-            .isEqualTo(Limit.limit(3));
-    }
-
-    @Test
-    public void ofShouldTakeNegativeValueAsUnlimited() {
-        assertThat(Limit.from(-1))
-            .isEqualTo(Limit.unlimited());
-    }
-
-    @Test
-    public void ofShouldTakeZeroValueAsUnlimited() {
-        assertThat(Limit.from(0))
-            .isEqualTo(Limit.unlimited());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/streams/OffsetTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/OffsetTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/OffsetTest.java
deleted file mode 100644
index 45d8e6d..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/OffsetTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-
-import org.junit.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class OffsetTest {
-
-    public static final int VALUE = 18;
-
-    @Test
-    public void shouldMatchBeanContract() {
-        EqualsVerifier.forClass(Offset.class)
-            .verify();
-    }
-
-    @Test
-    public void fromZeroShouldBeEquivalentToNone() {
-        assertThat(Offset.from(0))
-            .isEqualTo(Offset.none());
-    }
-
-    @Test
-    public void getOffsetShouldReturnContainedValue() {
-        assertThat(Offset.from(VALUE).getOffset())
-            .isEqualTo(VALUE);
-    }
-
-    @Test
-    public void fromOptionalShouldBeEquivalentToFromValueWhenPresent() {
-        assertThat(Offset.from(Optional.of(VALUE)))
-            .isEqualTo(Offset.from(VALUE));
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/resources/testcontainers.properties
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/resources/testcontainers.properties b/server/container/util-java8/src/test/resources/testcontainers.properties
deleted file mode 100644
index ec999c5..0000000
--- a/server/container/util-java8/src/test/resources/testcontainers.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-# Checks are disable due to space parsing error
-# We should remove this file when upgrading to upcoming 1.4.0 version of testscontainer
-# See
-checks.disable=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/util/pom.xml b/server/container/util/pom.xml
index a7af883..d10a795 100644
--- a/server/container/util/pom.xml
+++ b/server/container/util/pom.xml
@@ -34,6 +34,23 @@
 
     <dependencies>
         <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mime4j-dom</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.dpaukov</groupId>
+            <artifactId>combinatoricslib3</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>throwing-lambdas</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.steveash.guavate</groupId>
+            <artifactId>guavate</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
@@ -46,6 +63,15 @@
             <artifactId>commons-io</artifactId>
         </dependency>
         <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>nl.jqno.equalsverifier</groupId>
+            <artifactId>equalsverifier</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/ClassLoaderUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/ClassLoaderUtils.java b/server/container/util/src/main/java/org/apache/james/util/ClassLoaderUtils.java
new file mode 100644
index 0000000..68d9b08
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/ClassLoaderUtils.java
@@ -0,0 +1,54 @@
+/****************************************************************
+ * 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.util;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import javax.mail.util.SharedByteArrayInputStream;
+
+import org.apache.commons.io.IOUtils;
+
+public class ClassLoaderUtils {
+    public static String getSystemResourceAsString(String filename, Charset charset) {
+        try {
+            return IOUtils.toString(ClassLoader.getSystemResourceAsStream(filename), charset);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String getSystemResourceAsString(String filename) {
+        return getSystemResourceAsString(filename, StandardCharsets.US_ASCII);
+    }
+
+    public static byte[] getSystemResourceAsByteArray(String filename) {
+        try {
+            return IOUtils.toByteArray(ClassLoader.getSystemResourceAsStream(filename));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static SharedByteArrayInputStream getSystemResourceAsSharedStream(String filename) {
+        return new SharedByteArrayInputStream(getSystemResourceAsByteArray(filename));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java b/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
new file mode 100644
index 0000000..d2e83af
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public class CompletableFutureUtil {
+
+    public static <T> CompletableFuture<Optional<T>> unwrap(CompletableFuture<Optional<CompletableFuture<T>>> base) {
+        return base.thenCompose(
+            optional -> optional.map(future -> future.thenApply(Optional::of))
+                .orElse(CompletableFuture.completedFuture(Optional.empty())));
+    }
+
+    @SafeVarargs
+    public static <T> CompletableFuture<Stream<T>> allOfArray(CompletableFuture<T>... futures) {
+        return allOf(Stream.of(futures));
+    }
+
+    public static <T, U, V> CompletableFuture<V> combine(CompletableFuture<T> t, CompletableFuture<U> u, BiFunction<T,U,V> combiner) {
+        return t.thenCompose(valueT ->
+            u.thenApply(valueU -> combiner.apply(valueT, valueU)));
+    }
+
+    public static <T> CompletableFuture<Stream<T>> allOf(Stream<CompletableFuture<T>> futureStream) {
+        return futureStream
+            .map((CompletableFuture<T> future) -> future.thenApply(Stream::of))
+            .parallel()
+            .reduce((future1, future2) ->
+            future1.thenCompose(
+                stream1 -> future2.thenCompose(
+                    stream2 -> {
+                        Stream<T> concatStream = Stream.concat(stream1, stream2);
+                        return CompletableFuture.completedFuture(concatStream);
+                    })))
+            .orElse(CompletableFuture.completedFuture(Stream.of()));
+    }
+
+    public static <R, T> CompletableFuture<Stream<R>> chainAll(Stream<T> futureStream,
+        Function<T, CompletableFuture<R>> transformationToChain) {
+        return futureStream
+            .map(t -> (Supplier<CompletableFuture<R>>) (() -> transformationToChain.apply(t)))
+            .reduce(CompletableFuture.<Stream<R>>completedFuture(Stream.of()),
+                (accumulator, supplier) ->
+                    accumulator.thenCompose(
+                        accumulatedStream ->
+                            supplier.get()
+                                .thenCompose(r ->
+                                    CompletableFuture.completedFuture(Stream.<R>concat(accumulatedStream, Stream.of(r))))
+                    ),
+                getCompletableFutureBinaryOperator());
+    }
+
+    private static <R> BinaryOperator<CompletableFuture<Stream<R>>> getCompletableFutureBinaryOperator() {
+        return (future1, future2) ->
+            future1.thenCompose(stream1 ->
+                future2.<Stream<R>>thenCompose(stream2 ->
+                    CompletableFuture.completedFuture(Stream.concat(stream1, stream2))));
+    }
+
+    public static <T> CompletableFuture<Stream<T>> performOnAll(CompletableFuture<Stream<T>> futurStream, Function<T, CompletableFuture<Void>> action) {
+        return thenComposeOnAll(futurStream, value ->
+            keepValue(() ->
+                action.apply(value),
+                value));
+    }
+
+    public static <T, U> CompletableFuture<Stream<U>> thenComposeOnAll(CompletableFuture<Stream<T>> futurStream, Function<T, CompletableFuture<U>> action) {
+        return futurStream
+            .thenCompose(stream ->
+                CompletableFutureUtil.allOf(
+                    stream.map(action)));
+    }
+
+    public static <T, U> CompletableFuture<Stream<U>> map(CompletableFuture<Stream<T>> futurStream, Function<T, U> action) {
+        return futurStream
+            .thenApply(stream ->
+                stream.map(action));
+    }
+
+    public static <T> CompletableFuture<Optional<T>> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream) {
+        return futureStream.thenApply(stream -> stream.reduce(binaryOperator));
+    }
+
+    public static <T> CompletableFuture<T> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream, T emptyAccumulator) {
+        return futureStream.thenApply(stream -> stream.reduce(binaryOperator).orElse(emptyAccumulator));
+    }
+
+    public static <T> CompletableFuture<T> keepValue(Supplier<CompletableFuture<Void>> supplier, T value) {
+        return supplier.get().thenApply(any -> value);
+    }
+
+    public static <T> Function<Boolean, CompletableFuture<Boolean>> composeIfTrue(Supplier<CompletableFuture<T>> composeOperation) {
+        return b -> {
+            if (b) {
+                return composeOperation.get().thenApply(any -> b);
+            }
+            return CompletableFuture.completedFuture(b);
+        };
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[03/14] james-project git commit: JAMES-2502 fix Eclipse Photon build for mailets, utils and imap

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/test/java/org/apache/james/imap/encode/FakeImapSession.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/encode/FakeImapSession.java b/protocols/imap/src/test/java/org/apache/james/imap/encode/FakeImapSession.java
deleted file mode 100644
index bd7d053..0000000
--- a/protocols/imap/src/test/java/org/apache/james/imap/encode/FakeImapSession.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************
- * 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.imap.encode;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.james.imap.api.ImapSessionState;
-import org.apache.james.imap.api.process.ImapLineHandler;
-import org.apache.james.imap.api.process.ImapSession;
-import org.apache.james.imap.api.process.SelectedMailbox;
-
-public class FakeImapSession implements ImapSession {
-
-    private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
-
-    private SelectedMailbox selectedMailbox = null;
-
-    private final Map<String, Object> attributesByKey;
-
-    public FakeImapSession() {
-        this.attributesByKey = new ConcurrentHashMap<>();
-    }
-
-    @Override
-    public void logout() {
-        closeMailbox();
-        state = ImapSessionState.LOGOUT;
-    }
-
-    @Override
-    public void authenticated() {
-        this.state = ImapSessionState.AUTHENTICATED;
-    }
-
-    @Override
-    public void deselect() {
-        this.state = ImapSessionState.AUTHENTICATED;
-        closeMailbox();
-    }
-
-    @Override
-    public void selected(SelectedMailbox mailbox) {
-        this.state = ImapSessionState.SELECTED;
-        closeMailbox();
-        this.selectedMailbox = mailbox;
-    }
-
-    @Override
-    public SelectedMailbox getSelected() {
-        return this.selectedMailbox;
-    }
-
-    @Override
-    public ImapSessionState getState() {
-        return this.state;
-    }
-
-    public void closeMailbox() {
-        if (selectedMailbox != null) {
-            selectedMailbox.deselect();
-            selectedMailbox = null;
-        }
-    }
-
-    @Override
-    public Object getAttribute(String key) {
-        return attributesByKey.get(key);
-    }
-
-    @Override
-    public void setAttribute(String key, Object value) {
-        if (value == null) {
-            attributesByKey.remove(key);
-        } else {
-            attributesByKey.put(key, value);
-        }
-    }
-    
-    @Override
-    public boolean startTLS() {
-        return false;
-    }
-
-    @Override
-    public boolean supportStartTLS() {
-        return false;
-    }
-
-    @Override
-    public boolean isCompressionSupported() {
-        return false;
-    }
-
-    @Override
-    public boolean startCompression() {
-        return false;
-    }
-
-    @Override
-    public void pushLineHandler(ImapLineHandler lineHandler) {
-    }
-
-    @Override
-    public void popLineHandler() {
-        
-    }
-
-    @Override
-    public boolean isPlainAuthDisallowed() {
-        return false;
-    }
-
-    @Override
-    public boolean isTLSActive() {
-        return false;
-    }
-
-    @Override
-    public boolean supportMultipleNamespaces() {
-        return false;
-    }
-
-    @Override
-    public boolean isCompressionActive() {
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/core/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/core/pom.xml b/server/container/core/pom.xml
index 6f64917..ef1d3d3 100644
--- a/server/container/core/pom.xml
+++ b/server/container/core/pom.xml
@@ -49,8 +49,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <classifier>tests</classifier>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/metrics/metrics-es-reporter/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/metrics/metrics-es-reporter/pom.xml b/server/container/metrics/metrics-es-reporter/pom.xml
index dc3d11d..89b5e4a 100644
--- a/server/container/metrics/metrics-es-reporter/pom.xml
+++ b/server/container/metrics/metrics-es-reporter/pom.xml
@@ -40,8 +40,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/util-java8/src/test/java/org/apache/james/util/docker/Images.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/docker/Images.java b/server/container/util-java8/src/test/java/org/apache/james/util/docker/Images.java
deleted file mode 100644
index c252f1a..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/docker/Images.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/****************************************************************
- * 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.util.docker;
-
-public interface Images {
-    String FAKE_SMTP = "weave/rest-smtp-sink:latest";
-    String RABBITMQ = "rabbitmq:3.7.7";
-    String ELASTICSEARCH = "elasticsearch:2.4.6";
-    String NGINX = "nginx:1.15.1";
-    String TIKA = "linagora/docker-tikaserver:1.18-SNAPSHOT-plus-TIKA-2520";
-    String SPAMASSASSIN = "dinkel/spamassassin:3.4.0";
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java b/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java
deleted file mode 100644
index 59488c0..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************
- * 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.util.docker;
-
-import java.net.Socket;
-import java.time.Duration;
-import java.util.List;
-
-import javax.net.SocketFactory;
-
-import org.junit.Assume;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testcontainers.DockerClientFactory;
-import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.containers.wait.strategy.WaitStrategy;
-import org.testcontainers.images.builder.ImageFromDockerfile;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
-
-import com.github.dockerjava.api.command.InspectContainerResponse;
-import com.google.common.base.Strings;
-
-public class SwarmGenericContainer implements TestRule {
-    private static final Logger LOGGER = LoggerFactory.getLogger(SwarmGenericContainer.class);
-    private static final String DOCKER_CONTAINER = "DOCKER_CONTAINER";
-    private static final String NO_DOCKER_ENVIRONMENT = "Could not find a valid Docker environment.";
-    private static final String SKIPPING_TEST_CAUTION = "Skipping all docker tests as no Docker environment was found";
-
-    private GenericContainer<?> container;
-
-    public SwarmGenericContainer(String dockerImageName) {
-        try {
-            this.container = new GenericContainer<>(dockerImageName);
-        } catch (IllegalStateException e) {
-            logAndCheckSkipTest(e);
-        }
-    }
-
-    public SwarmGenericContainer(ImageFromDockerfile imageFromDockerfile) {
-        try {
-            this.container = new GenericContainer<>(imageFromDockerfile);
-        } catch (IllegalStateException e) {
-            logAndCheckSkipTest(e);
-        }
-    }
-    
-    private void logAndCheckSkipTest(IllegalStateException e) {
-        LOGGER.error("Cannot initial a docker container", e);
-        if (e.getMessage().startsWith(NO_DOCKER_ENVIRONMENT)) {
-            Assume.assumeTrue(SKIPPING_TEST_CAUTION, false);
-        }
-    }
-
-    public SwarmGenericContainer withAffinityToContainer() {
-        String containerEnv = System.getenv(DOCKER_CONTAINER);
-        if (Strings.isNullOrEmpty(containerEnv)) {
-            LOGGER.warn("'DOCKER_CONTAINER' environment variable not found, dockering without affinity");
-            return this;
-        }
-        List<String> envVariables = container.getEnv();
-        envVariables.add("affinity:container==" + container);
-        container.setEnv(envVariables);
-        return this;
-    }
-
-    public SwarmGenericContainer withEnv(String key, String value) {
-        container.addEnv(key, value);
-        return this;
-    }
-
-    public SwarmGenericContainer withExposedPorts(Integer... ports) {
-        container.withExposedPorts(ports);
-        return this;
-    }
-
-    public SwarmGenericContainer portBinding(int hostPort, int dockerPort) {
-        container.setPortBindings(ImmutableList.of("0.0.0.0:" + hostPort + ":" + dockerPort));
-        return this;
-    }
-
-    public SwarmGenericContainer waitingFor(WaitStrategy waitStrategy) {
-        container.waitingFor(waitStrategy);
-        return this;
-    }
-
-    public SwarmGenericContainer withStartupTimeout(Duration startupTimeout) {
-        container.withStartupTimeout(startupTimeout);
-        return this;
-    }
-
-    public SwarmGenericContainer withCommands(String... commands) {
-        container.withCommand(commands);
-        return this;
-    }
-
-    public void start() {
-        container.start();
-    }
-
-    public void stop() {
-        container.stop();
-    }
-
-    public void pause() {
-        DockerClientFactory.instance().client().pauseContainerCmd(container.getContainerInfo().getId());
-    }
-
-    public void unpause() {
-        DockerClientFactory.instance().client().unpauseContainerCmd(container.getContainerInfo().getId());
-    }
-
-    public Integer getMappedPort(int originalPort) {
-        return container.getMappedPort(originalPort);
-    }
-
-    @SuppressWarnings("deprecation")
-    public String getContainerIp() {
-        return container.getContainerInfo().getNetworkSettings().getIpAddress();
-    }
-    
-    public String getHostIp() {
-        return container.getContainerIpAddress();
-    }
-
-    public InspectContainerResponse getContainerInfo() {
-        return container.getContainerInfo();
-    }
-
-    public boolean tryConnect(int port) {
-        try {
-            Socket socket = SocketFactory.getDefault().createSocket(getContainerIp(), port);
-            socket.close();
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    @Override
-    public Statement apply(Statement statement, Description description) {
-        return container.apply(statement, description);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/util/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/util/pom.xml b/server/container/util/pom.xml
index fadfca7..a7af883 100644
--- a/server/container/util/pom.xml
+++ b/server/container/util/pom.xml
@@ -38,6 +38,10 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+        </dependency>
+        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
         </dependency>
@@ -46,6 +50,11 @@
             <artifactId>commons-lang3</artifactId>
         </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>
@@ -61,11 +70,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/container/util/src/main/java/org/apache/james/util/MimeMessageUtil.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/MimeMessageUtil.java b/server/container/util/src/main/java/org/apache/james/util/MimeMessageUtil.java
new file mode 100644
index 0000000..93715f8
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/MimeMessageUtil.java
@@ -0,0 +1,55 @@
+/****************************************************************
+ * 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.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+public class MimeMessageUtil {
+
+    public static String asString(MimeMessage mimeMessage) throws Exception {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        mimeMessage.writeTo(byteArrayOutputStream);
+        return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8);
+    }
+
+    public static MimeMessage defaultMimeMessage() {
+        return new MimeMessage(Session.getDefaultInstance(new Properties()));
+    }
+
+    public static MimeMessage mimeMessageFromStream(InputStream inputStream) throws MessagingException {
+        return new MimeMessage(Session.getDefaultInstance(new Properties()), inputStream);
+    }
+
+    public static MimeMessage mimeMessageFromBytes(byte[] bytes) throws MessagingException {
+        return mimeMessageFromStream(new ByteArrayInputStream(bytes));
+    }
+
+    public static MimeMessage mimeMessageFromString(String string) throws MessagingException {
+        return mimeMessageFromBytes(string.getBytes(StandardCharsets.UTF_8));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/data/data-ldap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-ldap-integration-testing/pom.xml b/server/data/data-ldap-integration-testing/pom.xml
index 63617e3..4b5919c 100644
--- a/server/data/data-ldap-integration-testing/pom.xml
+++ b/server/data/data-ldap-integration-testing/pom.xml
@@ -45,8 +45,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/mailet/integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/pom.xml b/server/mailet/integration-testing/pom.xml
index 3670525..0af81e4 100644
--- a/server/mailet/integration-testing/pom.xml
+++ b/server/mailet/integration-testing/pom.xml
@@ -35,8 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index b1b61e3..21c6e8a 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -53,7 +53,6 @@
         <module>container/metrics/metrics-es-reporter</module>
         <module>container/spring</module>
         <module>container/util</module>
-        <module>container/util-java8</module>
 
         <module>data/data-api</module>
         <module>data/data-cassandra</module>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/protocols/jmap/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/pom.xml b/server/protocols/jmap/pom.xml
index 31e1ec8..f8eebce 100644
--- a/server/protocols/jmap/pom.xml
+++ b/server/protocols/jmap/pom.xml
@@ -65,8 +65,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/protocols/webadmin/webadmin-mailqueue/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailqueue/pom.xml b/server/protocols/webadmin/webadmin-mailqueue/pom.xml
index 032fba8..5964a75 100644
--- a/server/protocols/webadmin/webadmin-mailqueue/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailqueue/pom.xml
@@ -35,8 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/protocols/webadmin/webadmin-mailrepository/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/pom.xml b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
index 2e27115..abc9d2f 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
@@ -35,8 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/queue/queue-rabbitmq/pom.xml
----------------------------------------------------------------------
diff --git a/server/queue/queue-rabbitmq/pom.xml b/server/queue/queue-rabbitmq/pom.xml
index 3f7e708..7244a13 100644
--- a/server/queue/queue-rabbitmq/pom.xml
+++ b/server/queue/queue-rabbitmq/pom.xml
@@ -40,8 +40,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/testing/pom.xml b/server/testing/pom.xml
index 50623d2..c689d7b 100644
--- a/server/testing/pom.xml
+++ b/server/testing/pom.xml
@@ -37,8 +37,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/testing/src/main/java/org/apache/james/util/docker/Images.java
----------------------------------------------------------------------
diff --git a/server/testing/src/main/java/org/apache/james/util/docker/Images.java b/server/testing/src/main/java/org/apache/james/util/docker/Images.java
new file mode 100644
index 0000000..c252f1a
--- /dev/null
+++ b/server/testing/src/main/java/org/apache/james/util/docker/Images.java
@@ -0,0 +1,29 @@
+/****************************************************************
+ * 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.util.docker;
+
+public interface Images {
+    String FAKE_SMTP = "weave/rest-smtp-sink:latest";
+    String RABBITMQ = "rabbitmq:3.7.7";
+    String ELASTICSEARCH = "elasticsearch:2.4.6";
+    String NGINX = "nginx:1.15.1";
+    String TIKA = "linagora/docker-tikaserver:1.18-SNAPSHOT-plus-TIKA-2520";
+    String SPAMASSASSIN = "dinkel/spamassassin:3.4.0";
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/server/testing/src/main/java/org/apache/james/util/docker/SwarmGenericContainer.java
----------------------------------------------------------------------
diff --git a/server/testing/src/main/java/org/apache/james/util/docker/SwarmGenericContainer.java b/server/testing/src/main/java/org/apache/james/util/docker/SwarmGenericContainer.java
new file mode 100644
index 0000000..59488c0
--- /dev/null
+++ b/server/testing/src/main/java/org/apache/james/util/docker/SwarmGenericContainer.java
@@ -0,0 +1,164 @@
+/****************************************************************
+ * 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.util.docker;
+
+import java.net.Socket;
+import java.time.Duration;
+import java.util.List;
+
+import javax.net.SocketFactory;
+
+import org.junit.Assume;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.WaitStrategy;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+import com.github.dockerjava.api.command.InspectContainerResponse;
+import com.google.common.base.Strings;
+
+public class SwarmGenericContainer implements TestRule {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SwarmGenericContainer.class);
+    private static final String DOCKER_CONTAINER = "DOCKER_CONTAINER";
+    private static final String NO_DOCKER_ENVIRONMENT = "Could not find a valid Docker environment.";
+    private static final String SKIPPING_TEST_CAUTION = "Skipping all docker tests as no Docker environment was found";
+
+    private GenericContainer<?> container;
+
+    public SwarmGenericContainer(String dockerImageName) {
+        try {
+            this.container = new GenericContainer<>(dockerImageName);
+        } catch (IllegalStateException e) {
+            logAndCheckSkipTest(e);
+        }
+    }
+
+    public SwarmGenericContainer(ImageFromDockerfile imageFromDockerfile) {
+        try {
+            this.container = new GenericContainer<>(imageFromDockerfile);
+        } catch (IllegalStateException e) {
+            logAndCheckSkipTest(e);
+        }
+    }
+    
+    private void logAndCheckSkipTest(IllegalStateException e) {
+        LOGGER.error("Cannot initial a docker container", e);
+        if (e.getMessage().startsWith(NO_DOCKER_ENVIRONMENT)) {
+            Assume.assumeTrue(SKIPPING_TEST_CAUTION, false);
+        }
+    }
+
+    public SwarmGenericContainer withAffinityToContainer() {
+        String containerEnv = System.getenv(DOCKER_CONTAINER);
+        if (Strings.isNullOrEmpty(containerEnv)) {
+            LOGGER.warn("'DOCKER_CONTAINER' environment variable not found, dockering without affinity");
+            return this;
+        }
+        List<String> envVariables = container.getEnv();
+        envVariables.add("affinity:container==" + container);
+        container.setEnv(envVariables);
+        return this;
+    }
+
+    public SwarmGenericContainer withEnv(String key, String value) {
+        container.addEnv(key, value);
+        return this;
+    }
+
+    public SwarmGenericContainer withExposedPorts(Integer... ports) {
+        container.withExposedPorts(ports);
+        return this;
+    }
+
+    public SwarmGenericContainer portBinding(int hostPort, int dockerPort) {
+        container.setPortBindings(ImmutableList.of("0.0.0.0:" + hostPort + ":" + dockerPort));
+        return this;
+    }
+
+    public SwarmGenericContainer waitingFor(WaitStrategy waitStrategy) {
+        container.waitingFor(waitStrategy);
+        return this;
+    }
+
+    public SwarmGenericContainer withStartupTimeout(Duration startupTimeout) {
+        container.withStartupTimeout(startupTimeout);
+        return this;
+    }
+
+    public SwarmGenericContainer withCommands(String... commands) {
+        container.withCommand(commands);
+        return this;
+    }
+
+    public void start() {
+        container.start();
+    }
+
+    public void stop() {
+        container.stop();
+    }
+
+    public void pause() {
+        DockerClientFactory.instance().client().pauseContainerCmd(container.getContainerInfo().getId());
+    }
+
+    public void unpause() {
+        DockerClientFactory.instance().client().unpauseContainerCmd(container.getContainerInfo().getId());
+    }
+
+    public Integer getMappedPort(int originalPort) {
+        return container.getMappedPort(originalPort);
+    }
+
+    @SuppressWarnings("deprecation")
+    public String getContainerIp() {
+        return container.getContainerInfo().getNetworkSettings().getIpAddress();
+    }
+    
+    public String getHostIp() {
+        return container.getContainerIpAddress();
+    }
+
+    public InspectContainerResponse getContainerInfo() {
+        return container.getContainerInfo();
+    }
+
+    public boolean tryConnect(int port) {
+        try {
+            Socket socket = SocketFactory.getDefault().createSocket(getContainerIp(), port);
+            socket.close();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    @Override
+    public Statement apply(Statement statement, Description description) {
+        return container.apply(statement, description);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/third-party/spamassassin/pom.xml
----------------------------------------------------------------------
diff --git a/third-party/spamassassin/pom.xml b/third-party/spamassassin/pom.xml
index 4b1da22..9b1c7a6 100644
--- a/third-party/spamassassin/pom.xml
+++ b/third-party/spamassassin/pom.xml
@@ -31,6 +31,11 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>javax-mail-extension</artifactId>
             <type>test-jar</type>
             <scope>test</scope>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[10/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java b/server/container/util-java8/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java
deleted file mode 100644
index 6f80e76..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/****************************************************************
- * 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.util.date;
-
-import java.time.ZonedDateTime;
-
-import javax.inject.Provider;
-
-public interface ZonedDateTimeProvider extends Provider<ZonedDateTime> {
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java b/server/container/util-java8/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
deleted file mode 100644
index 74bb660..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/****************************************************************
- * 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.util.mime;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import javax.mail.internet.MimeMessage;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.james.mime4j.dom.Body;
-import org.apache.james.mime4j.dom.Entity;
-import org.apache.james.mime4j.dom.Multipart;
-import org.apache.james.mime4j.dom.TextBody;
-
-import com.github.fge.lambdas.Throwing;
-import com.github.fge.lambdas.functions.ThrowingFunction;
-
-public class MessageContentExtractor {
-
-    public static final String CONTENT_ID = "Content-ID";
-    public static final String MULTIPART_ALTERNATIVE = "multipart/alternative";
-    public static final String TEXT_HTML = "text/html";
-    public static final String TEXT_PLAIN = "text/plain";
-
-    public MessageContent extract(org.apache.james.mime4j.dom.Message message) throws IOException {
-        Body body = message.getBody();
-        if (body instanceof TextBody) {
-            return parseTextBody(message, (TextBody)body);
-        }
-        if (body instanceof Multipart) {
-            return parseMultipart(message, (Multipart)body);
-        }
-        return MessageContent.empty();
-    }
-
-    private MessageContent parseTextBody(Entity entity, TextBody textBody) throws IOException {
-        Optional<String> bodyContent = asString(textBody);
-        if (TEXT_HTML.equals(entity.getMimeType())) {
-            return MessageContent.ofHtmlOnly(bodyContent);
-        }
-        return MessageContent.ofTextOnly(bodyContent);
-    }
-
-    private MessageContent parseMultipart(Entity entity, Multipart multipart) throws IOException {
-        MessageContent messageContent = parseMultipartContent(entity, multipart);
-        if (!messageContent.isEmpty()) {
-            return messageContent;
-        }
-        return parseFirstFoundMultipart(multipart);
-    }
-
-    private MessageContent parseMultipartContent(Entity entity, Multipart multipart) throws IOException {
-        switch (entity.getMimeType()) {
-        case MULTIPART_ALTERNATIVE:
-            return retrieveHtmlAndPlainTextContent(multipart);
-        default:
-            return retrieveFirstReadablePart(multipart);
-        }
-    }
-
-    private MessageContent parseFirstFoundMultipart(Multipart multipart) throws IOException {
-        ThrowingFunction<Entity, MessageContent> parseMultipart = firstPart -> parseMultipart(firstPart, (Multipart)firstPart.getBody());
-        return multipart.getBodyParts()
-            .stream()
-            .filter(part -> part.getBody() instanceof Multipart)
-            .findFirst()
-            .map(Throwing.function(parseMultipart).sneakyThrow())
-            .orElse(MessageContent.empty());
-    }
-
-    private Optional<String> asString(TextBody textBody) throws IOException {
-        return Optional.ofNullable(IOUtils.toString(textBody.getInputStream(), charset(Optional.ofNullable(textBody.getMimeCharset()))));
-    }
-
-    private Charset charset(Optional<String> charset) {
-        return charset
-                .map(Charset::forName)
-                .orElse(org.apache.james.mime4j.Charsets.DEFAULT_CHARSET);
-    }
-
-    private MessageContent retrieveHtmlAndPlainTextContent(Multipart multipart) throws IOException {
-        Optional<String> textBody = getFirstMatchingTextBody(multipart, TEXT_PLAIN);
-        Optional<String> htmlBody = getFirstMatchingTextBody(multipart, TEXT_HTML);
-        MessageContent directChildTextBodies = new MessageContent(textBody, htmlBody);
-        if (!directChildTextBodies.isComplete()) {
-            MessageContent fromInnerMultipart = parseFirstFoundMultipart(multipart);
-            return directChildTextBodies.merge(fromInnerMultipart);
-        }
-        return directChildTextBodies;
-    }
-
-    private MessageContent retrieveFirstReadablePart(Multipart multipart) throws IOException {
-        return retrieveFirstReadablePartMatching(multipart, this::isNotAttachment)
-            .orElseGet(() -> retrieveFirstReadablePartMatching(multipart, this::isInlinedWithoutCid)
-                .orElse(MessageContent.empty()));
-    }
-
-    private Optional<MessageContent> retrieveFirstReadablePartMatching(Multipart multipart, Predicate<Entity> predicate) {
-        return multipart.getBodyParts()
-            .stream()
-            .filter(predicate)
-            .flatMap(Throwing.function(this::extractContentIfReadable).sneakyThrow())
-            .findFirst();
-    }
-
-    private Stream<MessageContent> extractContentIfReadable(Entity entity) throws IOException {
-        if (TEXT_HTML.equals(entity.getMimeType()) && entity.getBody() instanceof TextBody) {
-            return Stream.of(
-                    MessageContent.ofHtmlOnly(asString((TextBody)entity.getBody())));
-        }
-        if (TEXT_PLAIN.equals(entity.getMimeType()) && entity.getBody() instanceof TextBody) {
-            return Stream.of(
-                    MessageContent.ofTextOnly(asString((TextBody)entity.getBody())));
-        }
-        if (entity.isMultipart() && entity.getBody() instanceof Multipart) {
-            MessageContent innerMultipartContent = parseMultipart(entity, (Multipart)entity.getBody());
-            if (!innerMultipartContent.isEmpty()) {
-                return Stream.of(innerMultipartContent);
-            }
-        }
-        return Stream.empty();
-    }
-
-    private Optional<String> getFirstMatchingTextBody(Multipart multipart, String mimeType) throws IOException {
-        Optional<String> firstMatchingTextBody = getFirstMatchingTextBody(multipart, mimeType, this::isNotAttachment);
-        if (firstMatchingTextBody.isPresent()) {
-            return firstMatchingTextBody;
-        }
-        Optional<String> fallBackInlinedBodyWithoutCid = getFirstMatchingTextBody(multipart, mimeType, this::isInlinedWithoutCid);
-        return fallBackInlinedBodyWithoutCid;
-    }
-
-    private Optional<String> getFirstMatchingTextBody(Multipart multipart, String mimeType, Predicate<Entity> condition) {
-        Function<TextBody, Optional<String>> textBodyOptionalFunction = Throwing
-            .function(this::asString).sneakyThrow();
-
-        return multipart.getBodyParts()
-            .stream()
-            .filter(part -> mimeType.equals(part.getMimeType()))
-            .filter(condition)
-            .map(Entity::getBody)
-            .filter(TextBody.class::isInstance)
-            .map(TextBody.class::cast)
-            .findFirst()
-            .flatMap(textBodyOptionalFunction);
-    }
-
-    private boolean isNotAttachment(Entity part) {
-        return part.getDispositionType() == null;
-    }
-
-    private boolean isInlinedWithoutCid(Entity part) {
-        return Objects.equals(part.getDispositionType(), MimeMessage.INLINE)
-            && part.getHeader().getField(CONTENT_ID) == null;
-    }
-
-    public static class MessageContent {
-        private final Optional<String> textBody;
-        private final Optional<String> htmlBody;
-
-        public MessageContent(Optional<String> textBody, Optional<String> htmlBody) {
-            this.textBody = textBody;
-            this.htmlBody = htmlBody;
-        }
-
-        public static MessageContent ofTextOnly(Optional<String> textBody) {
-            return new MessageContent(textBody, Optional.empty());
-        }
-
-        public static MessageContent ofHtmlOnly(Optional<String> htmlBody) {
-            return new MessageContent(Optional.empty(), htmlBody);
-        }
-
-        public static MessageContent empty() {
-            return new MessageContent(Optional.empty(), Optional.empty());
-        }
-        
-        public Optional<String> getTextBody() {
-            return textBody;
-        }
-
-        public Optional<String> getHtmlBody() {
-            return htmlBody;
-        }
-        
-        public boolean isEmpty() {
-            return equals(empty());
-        }
-
-        public boolean isComplete() {
-            return textBody.isPresent() && htmlBody.isPresent();
-        }
-
-        public MessageContent merge(MessageContent fromInnerMultipart) {
-            return new MessageContent(
-                    textBody.map(Optional::of).orElse(fromInnerMultipart.getTextBody()),
-                    htmlBody.map(Optional::of).orElse(fromInnerMultipart.getHtmlBody()));
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (other == null || !(other instanceof MessageContent)) {
-                return false;
-            }
-            MessageContent otherMessageContent = (MessageContent)other;
-            return Objects.equals(this.textBody, otherMessageContent.textBody)
-                    && Objects.equals(this.htmlBody, otherMessageContent.htmlBody);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/streams/Iterators.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Iterators.java b/server/container/util-java8/src/main/java/org/apache/james/util/streams/Iterators.java
deleted file mode 100644
index ba3a06b..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Iterators.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import java.util.Iterator;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-public class Iterators {
-
-    public static <T> Stream<T> toStream(Iterator<T> iterator) {
-        Iterable<T> iterable = () -> iterator;
-        return StreamSupport.stream(iterable.spliterator(), false);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/streams/JamesCollectors.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/streams/JamesCollectors.java b/server/container/util-java8/src/main/java/org/apache/james/util/streams/JamesCollectors.java
deleted file mode 100644
index e705063..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/streams/JamesCollectors.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import java.util.Collection;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.stream.Collector;
-import java.util.stream.Stream;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-
-public class JamesCollectors {
-    public static <D> Collector<D, ?, Stream<Collection<D>>> chunker(int chunkSize) {
-        return new ChunkCollector<>(chunkSize);
-    }
-
-    public static class ChunkCollector<D> implements Collector<D, Multimap<Integer, D>, Stream<Collection<D>>> {
-        private final int chunkSize;
-        private final AtomicInteger counter;
-
-        private ChunkCollector(int chunkSize) {
-            Preconditions.checkArgument(chunkSize > 0, "ChunkSize should be strictly positive");
-            this.chunkSize = chunkSize;
-            this.counter = new AtomicInteger(-1);
-        }
-
-        @Override
-        public Supplier<Multimap<Integer, D>> supplier() {
-            return ArrayListMultimap::create;
-        }
-
-        @Override
-        public BiConsumer<Multimap<Integer, D>, D> accumulator() {
-            return (accumulator, value) -> accumulator.put(counter.incrementAndGet() / chunkSize, value);
-        }
-
-        @Override
-        public BinaryOperator<Multimap<Integer, D>> combiner() {
-            return (accumulator1, accumulator2) -> {
-                accumulator1.putAll(accumulator2);
-                return accumulator1;
-            };
-        }
-
-        @Override
-        public Function<Multimap<Integer, D>, Stream<Collection<D>>> finisher() {
-            return accumulator -> accumulator.asMap().values().stream();
-        }
-
-        @Override
-        public Set<Characteristics> characteristics() {
-            return ImmutableSet.of();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/streams/Limit.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Limit.java b/server/container/util-java8/src/main/java/org/apache/james/util/streams/Limit.java
deleted file mode 100644
index 268ed5e..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Limit.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import com.google.common.base.Preconditions;
-
-public class Limit {
-
-    public static Limit from(int limit) {
-        if (limit > 0) {
-            return new Limit(Optional.of(limit));
-        } else {
-            return unlimited();
-        }
-    }
-
-    public static Limit from(Optional<Integer> limit) {
-        return limit.map(Limit::from)
-            .orElse(unlimited());
-    }
-
-    public static Limit unlimited() {
-        return new Limit(Optional.empty());
-    }
-
-    public static Limit limit(int limit) {
-        Preconditions.checkArgument(limit > 0, "limit should be positive");
-        return new Limit(Optional.of(limit));
-    }
-
-    private final Optional<Integer> limit;
-
-    private Limit(Optional<Integer> limit) {
-        this.limit = limit;
-    }
-
-    public Optional<Integer> getLimit() {
-        return limit;
-    }
-
-    public <T> Stream<T> applyOnStream(Stream<T> stream) {
-        return limit
-            .map(stream::limit)
-            .orElse(stream);
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof Limit) {
-            Limit other = (Limit) o;
-            return Objects.equals(limit, other.limit);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(limit);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/streams/Offset.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Offset.java b/server/container/util-java8/src/main/java/org/apache/james/util/streams/Offset.java
deleted file mode 100644
index 109ecae..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/streams/Offset.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- * 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.util.streams;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import com.google.common.base.Preconditions;
-
-public class Offset {
-
-    public static Offset from(Optional<Integer> offset) {
-        return offset.map(Offset::from)
-            .orElse(none());
-    }
-
-    public static Offset none() {
-        return new Offset(0);
-    }
-
-    public static Offset from(int offset) {
-        Preconditions.checkArgument(offset >= 0, "offset should be positive");
-        return new Offset(offset);
-    }
-
-    private final int offset;
-
-    private Offset(int offset) {
-        this.offset = offset;
-    }
-
-    public int getOffset() {
-        return offset;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof Offset) {
-            Offset other = (Offset) o;
-            return Objects.equals(this.offset, other.offset);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(offset);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityChecker.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityChecker.java b/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityChecker.java
deleted file mode 100644
index 15976e9..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityChecker.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Set;
-import java.util.function.BinaryOperator;
-
-import org.apache.commons.lang3.tuple.Pair;
-import org.paukov.combinatorics3.Generator;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.base.Preconditions;
-
-public class CommutativityChecker<T> {
-    private final Set<T> valuesToTest;
-    private final BinaryOperator<T> operationToTest;
-
-    public CommutativityChecker(Set<T> valuesToTest, BinaryOperator<T> operationToTest) {
-        Preconditions.checkNotNull(valuesToTest);
-        Preconditions.checkNotNull(operationToTest);
-        Preconditions.checkArgument(valuesToTest.size() > 1, "You must to pass more than one value to check commutativity");
-        this.valuesToTest = valuesToTest;
-        this.operationToTest = operationToTest;
-    }
-
-    public Set<Pair<T, T>> findNonCommutativeInput() {
-        return Generator.combination(valuesToTest)
-            .simple(2)
-            .stream()
-            .map(list -> Pair.of(list.get(0), list.get(1)))
-            .filter(this::isNotCommutative)
-            .collect(Guavate.toImmutableSet());
-    }
-
-    private boolean isNotCommutative(Pair<T, T> pair) {
-        T leftThenRight = operationToTest.apply(pair.getLeft(), pair.getRight());
-        T rightThenLeft = operationToTest.apply(pair.getRight(), pair.getLeft());
-        return !leftThenRight.equals(rightThenLeft);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityCheckerTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
deleted file mode 100644
index a77b8e5..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.Set;
-import java.util.function.BinaryOperator;
-
-import org.apache.commons.lang3.tuple.Pair;
-import org.junit.Test;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
-
-public class CommutativityCheckerTest {
-    @Test
-    public void constructorShouldThrowWhenNullValuesToTest() throws Exception {
-        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
-
-        assertThatThrownBy(() -> new CommutativityChecker<>(null, binaryOperator))
-            .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void constructorShouldThrowWhenEmptyValuesToTest() throws Exception {
-        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
-
-        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(), binaryOperator))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void constructorShouldThrowWhenSingleValueToTest() throws Exception {
-        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
-
-        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(0), binaryOperator))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    public void constructorShouldThrowWhenNullOperation() throws Exception {
-        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(0, 1), null))
-            .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    public void findNonCommutativeInputShouldReturnEmptyWhenCommutativeOperation() throws Exception {
-        Set<Integer> integers = ImmutableSet.of(5, 4, 3, 2, 1);
-        BinaryOperator<Integer> commutativeOperator = (a, b) -> a + b;
-        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, commutativeOperator);
-
-        assertThat(commutativityChecker.findNonCommutativeInput()).isEmpty();
-    }
-
-    @Test
-    public void findNonCommutativeInputShouldReturnDataWhenNonCommutativeOperation() throws Exception {
-        Set<Integer> integers = ImmutableSet.of(2, 1);
-        BinaryOperator<Integer> nonCommutativeOperator = (a, b) -> 2 * a + b;
-        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, nonCommutativeOperator);
-
-        assertThat(commutativityChecker.findNonCommutativeInput())
-            .containsOnly(Pair.of(2, 1));
-    }
-
-    @Test
-    public void findNonCommutativeInputShouldNotReturnStableValues() throws Exception {
-        Set<Integer> integers = ImmutableSet.of(0, 1, 2);
-        BinaryOperator<Integer> nonCommutativeOperatorWithStableValues = (a, b) -> a * a + b;
-        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, nonCommutativeOperatorWithStableValues);
-
-        assertThat(commutativityChecker.findNonCommutativeInput())
-            .containsOnly(Pair.of(1, 2),
-                Pair.of(0, 2));
-    }
-
-    @Test
-    public void findNonCommutativeInputShouldReturnEmptyWhenNonCommutativeOperationButOnlyStableValues() throws Exception {
-        Set<Integer> stableValues = ImmutableSet.of(0, 1);
-        BinaryOperator<Integer> nonCommutativeOperatorWithStableValues = (a, b) -> a * a + b;
-        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(stableValues, nonCommutativeOperatorWithStableValues);
-
-        assertThat(commutativityChecker.findNonCommutativeInput()).isEmpty();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
deleted file mode 100644
index c0b892c..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Supplier;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.testcontainers.shaded.com.google.common.base.Throwables;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-
-public class CompletableFutureUtilTest {
-    private ExecutorService executorService;
-
-    @Before
-    public void setUp() {
-        executorService = Executors.newFixedThreadPool(4);
-    }
-
-    @After
-    public void tearDown() {
-        executorService.shutdownNow();
-    }
-
-    @Test
-    public void combineShouldReturnCombinationOfBothSuppliedFutures() {
-        int value1 = 18;
-        int value2 = 12;
-
-        assertThat(CompletableFutureUtil.combine(
-            CompletableFuture.completedFuture(value1),
-            CompletableFuture.completedFuture(value2),
-            (a, b) -> 2 * a + b)
-            .join())
-            .isEqualTo(2 * value1 + value2);
-
-    }
-
-    @Test
-    public void allOfShouldUnboxEmptyStream() {
-        assertThat(
-            CompletableFutureUtil.allOf(Stream.empty())
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void chainAllShouldPreserveExecutionOrder() {
-        int itemCount = 10;
-        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
-            .boxed()
-            .collect(Guavate.toImmutableList());
-
-        ConcurrentLinkedDeque<Integer> queue = new ConcurrentLinkedDeque<>();
-
-        CompletableFutureUtil.chainAll(ints.stream(),
-            i -> CompletableFuture.supplyAsync(() -> {
-                try {
-                    Thread.sleep(itemCount - i);
-                } catch (InterruptedException e) {
-                    throw Throwables.propagate(e);
-                }
-                queue.add(i);
-                return i;
-            }, executorService))
-            .join();
-
-        assertThat(queue)
-            .containsExactlyElementsOf(ints);
-    }
-
-    @Test
-    public void chainAllShouldNotThrowOnEmptyStream() {
-        Stream<Integer> result = CompletableFutureUtil.chainAll(Stream.<Integer>of(),
-            i -> CompletableFuture.supplyAsync(() -> i, executorService))
-            .join();
-
-        assertThat(result.collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void chainAllShouldPreserveOrder() {
-        int itemCount = 10;
-        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
-            .boxed()
-            .collect(Guavate.toImmutableList());
-
-        Stream<Integer> result = CompletableFutureUtil.chainAll(ints.stream(),
-            i -> CompletableFuture.supplyAsync(() -> i, executorService))
-            .join();
-
-        assertThat(result.collect(Guavate.toImmutableList()))
-            .containsExactlyElementsOf(ints);
-    }
-
-    @Test
-    public void allOfShouldUnboxStream() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        assertThat(
-            CompletableFutureUtil.allOf(
-                Stream.of(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsOnly(value1, value2, value3);
-    }
-
-    @Test
-    public void allOfShouldPreserveOrder() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        long value4 = 21L;
-        long value5 = 22L;
-        long value6 = 23L;
-        long value7 = 24L;
-        long value8 = 25L;
-        long value9 = 26L;
-        long value10 = 27L;
-        assertThat(
-            CompletableFutureUtil.allOf(
-                Stream.of(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3),
-                    CompletableFuture.completedFuture(value4),
-                    CompletableFuture.completedFuture(value5),
-                    CompletableFuture.completedFuture(value6),
-                    CompletableFuture.completedFuture(value7),
-                    CompletableFuture.completedFuture(value8),
-                    CompletableFuture.completedFuture(value9),
-                    CompletableFuture.completedFuture(value10)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(value1, value2, value3, value4, value5, value6, value7, value8, value9, value10);
-    }
-
-    @Test
-    public void allOfArrayShouldPreserveOrder() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        long value4 = 21L;
-        long value5 = 22L;
-        long value6 = 23L;
-        long value7 = 24L;
-        long value8 = 25L;
-        long value9 = 26L;
-        long value10 = 27L;
-        assertThat(
-            CompletableFutureUtil.allOfArray(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3),
-                    CompletableFuture.completedFuture(value4),
-                    CompletableFuture.completedFuture(value5),
-                    CompletableFuture.completedFuture(value6),
-                    CompletableFuture.completedFuture(value7),
-                    CompletableFuture.completedFuture(value8),
-                    CompletableFuture.completedFuture(value9),
-                    CompletableFuture.completedFuture(value10))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(value1, value2, value3, value4, value5, value6, value7, value8, value9, value10);
-    }
-
-    @Test
-    public void allOfArrayShouldUnboxNoArgs() {
-        assertThat(
-            CompletableFutureUtil.allOfArray()
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void allOfArrayShouldUnboxArray() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        assertThat(
-            CompletableFutureUtil.allOfArray(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsOnly(value1, value2, value3);
-    }
-
-    @Test
-    public void allOfShouldWorkOnVeryLargeStream() {
-        CompletableFutureUtil.allOf(
-            IntStream.range(0, 100000)
-                .boxed()
-                .map(CompletableFuture::completedFuture))
-            .join();
-    }
-
-    @Test
-    public void mapShouldMapOnStreamInsideACompletableFuturOfStream() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of(1, 2, 3));
-
-        assertThat(
-            CompletableFutureUtil.map(futurOfInteger, integer ->
-                integer * 2)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4, 6);
-    }
-
-    @Test
-    public void mapShouldReturnEmptyStreamWhenGivenAnEmptyStream() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of());
-
-        assertThat(
-            CompletableFutureUtil.map(futurOfInteger, integer ->
-                integer * 2)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void thenComposeOnAllShouldMapOnStreamInsideACompletableFuturOfStreamAndTransformTheResultingStreamOfCompletableFutureIntoACompletableOfStreamAndFlatIt() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of(1, 2, 3));
-
-        assertThat(
-            CompletableFutureUtil.thenComposeOnAll(futurOfInteger, integer ->
-                CompletableFuture.completedFuture(integer * 2))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4, 6);
-    }
-
-    @Test
-    public void thenComposeOnAllOnEmptyStreamShouldReturnAnEmptyStream() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of());
-
-        assertThat(
-            CompletableFutureUtil.thenComposeOnAll(futurOfInteger, integer ->
-                CompletableFuture.completedFuture(integer * 2))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void keepValueShouldCompleteWhenTheGivenCompletableFutureEnd() {
-        final AtomicInteger numOfFutureExecution = new AtomicInteger(0);
-
-        Supplier<CompletableFuture<Void>> future = () ->
-            CompletableFuture.runAsync(numOfFutureExecution::incrementAndGet);
-
-        assertThat(
-            CompletableFutureUtil.keepValue(future, 42)
-                .join())
-            .isEqualTo(42);
-
-        assertThat(
-            numOfFutureExecution.get())
-            .isEqualTo(1);
-    }
-
-    @Test
-    public void keepValueShouldReturnNullWithNullValue() {
-        Supplier<CompletableFuture<Void>> future = () ->
-            CompletableFuture.completedFuture(null);
-
-        assertThat(
-            CompletableFutureUtil.keepValue(future, null)
-                .join())
-            .isNull();
-    }
-
-    @Test
-    public void composeIfTrueShouldReturnTrueWhenTrue() {
-        assertThat(
-            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
-                .apply(true)
-                .join())
-            .isTrue();
-    }
-
-    @Test
-    public void composeIfTrueShouldReturnFalseWhenFalse() {
-        assertThat(
-            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
-                .apply(false)
-                .join())
-            .isFalse();
-    }
-
-    @Test
-    public void composeIfTrueShouldComposeWhenTrue() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-        CompletableFutureUtil.composeIfTrue(() -> {
-            atomicInteger.incrementAndGet();
-            return CompletableFuture.completedFuture(null);
-        })
-            .apply(true)
-            .join();
-
-        assertThat(atomicInteger.get()).isEqualTo(1);
-    }
-
-    @Test
-    public void composeIfTrueShouldNotComposeWhenFalse() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-        CompletableFutureUtil.composeIfTrue(() -> {
-            atomicInteger.incrementAndGet();
-            return CompletableFuture.completedFuture(null);
-        })
-            .apply(false)
-            .join();
-
-        assertThat(atomicInteger.get()).isEqualTo(0);
-    }
-
-    @Test
-    public void reduceShouldReturnEmptyWhenNoValue() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFutureUtil.<Long>allOfArray())
-                .join())
-            .isEmpty();
-    }
-
-    @Test
-    public void reduceShouldWork() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFutureUtil.allOfArray(
-                    CompletableFuture.completedFuture(1L),
-                    CompletableFuture.completedFuture(2L),
-                    CompletableFuture.completedFuture(3L)
-                ))
-                .join())
-            .contains(6L);
-    }
-
-    @Test
-    public void reduceShouldReturnIdentityAccumulatorWhenNoValue() {
-        long identityAccumulator = 0L;
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFutureUtil.<Long>allOfArray(),
-                identityAccumulator)
-                .join())
-            .isEqualTo(identityAccumulator);
-    }
-
-    @Test
-    public void reduceShouldWorkWithIdentityAccumulator() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFutureUtil.allOfArray(
-                    CompletableFuture.completedFuture(1L),
-                    CompletableFuture.completedFuture(2L),
-                    CompletableFuture.completedFuture(3L)
-                ),
-                0L)
-                .join())
-            .isEqualTo(6L);
-    }
-
-    @Test
-    public void unwrapShouldUnwrapWhenValue() {
-        assertThat(
-            CompletableFutureUtil.unwrap(
-                    CompletableFuture.completedFuture(Optional.of(CompletableFuture.completedFuture(1L))))
-                .join())
-            .isEqualTo(Optional.of(1L));
-    }
-
-    @Test
-    public void unwrapShouldUnwrapWhenEmpty() {
-        assertThat(
-            CompletableFutureUtil.unwrap(
-                    CompletableFuture.completedFuture(Optional.empty()))
-                .join())
-            .isEmpty();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/FluentFutureStreamTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
deleted file mode 100644
index 0877414..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.stream.Stream;
-
-import org.junit.Test;
-
-import com.github.steveash.guavate.Guavate;
-
-public class FluentFutureStreamTest {
-
-    @Test
-    public void ofFutureShouldConstructAFluentFutureStream() {
-        assertThat(
-            FluentFutureStream.ofFutures(
-                CompletableFuture.completedFuture(1),
-                CompletableFuture.completedFuture(2),
-                CompletableFuture.completedFuture(3))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void ofShouldConstructAFluentFutureStreamWhenProvidedAFutureOfStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void ofShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFuture() {
-        assertThat(
-            FluentFutureStream.of(
-                Stream.of(
-                    CompletableFuture.completedFuture(1),
-                    CompletableFuture.completedFuture(2),
-                    CompletableFuture.completedFuture(3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void ofNestedStreamsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfStream() {
-        assertThat(
-            FluentFutureStream.ofNestedStreams(
-                Stream.of(
-                    CompletableFuture.completedFuture(Stream.of(1, 2)),
-                    CompletableFuture.completedFuture(Stream.of()),
-                    CompletableFuture.completedFuture(Stream.of(3))))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-
-    @Test
-    public void ofOptionalsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfOptionals() {
-        assertThat(
-            FluentFutureStream.ofOptionals(
-                Stream.of(
-                    CompletableFuture.completedFuture(Optional.of(1)),
-                    CompletableFuture.completedFuture(Optional.of(2)),
-                    CompletableFuture.completedFuture(Optional.empty()),
-                    CompletableFuture.completedFuture(Optional.of(3))))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void completableFutureShouldReturnAFutureOfTheUnderLayingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .completableFuture()
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void mapShouldTransformUnderlyingValues() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> i + 1)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 3, 4);
-    }
-
-    @Test
-    public void flatMapShouldTransformUnderlyingValuesAndFlatMapResult() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .flatMap(i -> Stream.of(i, i + 1))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 2, 3, 3, 4);
-    }
-
-    @Test
-    public void flatMapOptionalShouldTransformUnderlyingValuesAndUnboxResult() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .flatMapOptional(i -> Optional.of(i + 1)
-                    .filter(j -> j % 2 == 0))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4);
-    }
-
-    @Test
-    public void reduceShouldGatherAllValuesOfTheUnderlyingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .reduce((a, b) -> a + b)
-                .join())
-            .contains(6);
-    }
-
-    @Test
-    public void reduceShouldGatherAllValuesOfTheUnderlyingStreamWithAnEmptyValue() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .reduce(0, (a, b) -> a + b)
-                .join())
-            .isEqualTo(6);
-    }
-
-    @Test
-    public void filterShouldBeAppliedOnTheUnderlyingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .filter(i -> i % 2 == 1)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 3);
-    }
-
-    @Test
-    public void thenComposeOnAllShouldTransformUnderlyingValuesAndComposeFutures() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .thenComposeOnAll(i -> CompletableFuture.completedFuture(i + 1))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 3, 4);
-    }
-
-    @Test
-    public void thenFlatComposeShouldTransformUnderlyingValuesAndComposeFuturesWithStreamUnboxing() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .thenFlatCompose(i -> CompletableFuture.completedFuture(Stream.of(i, i + 1)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 2, 3, 3, 4);
-    }
-
-    @Test
-    public void thenFlatComposeOnOptionalShouldTransformUnderlyingValuesAndComposeFuturesWithOptionalUnboxing() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .thenFlatComposeOnOptional(i -> CompletableFuture.completedFuture(Optional.of(i + 1)
-                    .filter(j -> j % 2 == 0)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4);
-    }
-
-    @Test
-    public void thenPerformOnAllShouldGenerateASynchronousSideEffectForAllElementsOfTheUnderlyingStream() {
-        ConcurrentLinkedDeque<Integer> sideEffects = new ConcurrentLinkedDeque<>();
-
-        FluentFutureStream.of(
-            CompletableFuture.completedFuture(
-                Stream.of(1, 2, 3)))
-            .performOnAll(i -> {
-                sideEffects.addLast(i);
-                return CompletableFuture.completedFuture(null);
-            })
-            .join()
-            .collect(Guavate.toImmutableList());
-
-        assertThat(sideEffects).containsOnly(1, 2, 3);
-    }
-
-    @Test
-    public void collectShouldReturnTheCollectionOfData() {
-        assertThat(
-            FluentFutureStream.of(
-                Stream.of(
-                    CompletableFuture.completedFuture(1),
-                    CompletableFuture.completedFuture(2),
-                    CompletableFuture.completedFuture(3)))
-                .collect(Guavate.toImmutableList())
-                .join())
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    public void collectShouldReturnEmptyWhenStreamIsEmpty() {
-        assertThat(
-            FluentFutureStream.ofFutures()
-                .collect(Guavate.toImmutableList())
-                .join())
-            .isEmpty();
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java
deleted file mode 100644
index 3702e5e..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.List;
-
-import org.junit.Test;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableListMultimap;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
-
-public class GuavaUtilsTest {
-
-    @Test
-    public void toMultimapShouldAcceptEmptyMaps() {
-        assertThat(GuavaUtils.toMultimap(ImmutableMap
-            .<String, List<String>>builder()
-            .build())
-            .asMap())
-            .isEqualTo(ImmutableMap.of());
-    }
-
-    @Test
-    public void toMultimapShouldAcceptSingleValuesMaps() {
-        assertThat(GuavaUtils.toMultimap(ImmutableMap
-            .<String, List<String>>builder()
-            .put("k1", ImmutableList.of("v1"))
-            .put("k2", ImmutableList.of("v2"))
-            .build())
-            .asMap())
-            .isEqualTo(ImmutableListMultimap.of(
-                "k1", "v1",
-                "k2", "v2")
-            .asMap());
-    }
-
-    @Test
-    public void toMultimapShouldAcceptMultiplesValuesMaps() {
-        assertThat(GuavaUtils.toMultimap(ImmutableMap
-            .<String, List<String>>builder()
-            .put("k1", ImmutableList.of("v1"))
-            .put("k2", ImmutableList.of("v2", "v2.1"))
-            .build())
-            .asMap())
-            .isEqualTo(ImmutableListMultimap.of(
-                "k1", "v1",
-                "k2", "v2",
-                "k2", "v2.1")
-                .asMap());
-    }
-
-    @Test
-    public void shouldStripEntriesWithEmptyList() {
-        assertThat(GuavaUtils.toMultimap(ImmutableMap
-            .<String, List<String>>builder()
-            .put("k1", ImmutableList.of())
-            .build())
-            .asMap())
-            .isEqualTo(ImmutableListMultimap.of().asMap());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/HostTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/HostTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/HostTest.java
deleted file mode 100644
index 3ebeaee..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/HostTest.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-public class HostTest {
-
-    private static final int DEFAULT_PORT = 154;
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void parseConfStringShouldParseConfWithIpAndPort() {
-        //Given
-        int expectedPort = 44;
-        String expectedIp = "142.145.254.111";
-        String ipAndPort = expectedIp + ":" + 44;
-
-        //When
-        Host actual = Host.parseConfString(ipAndPort);
-
-        //Then
-        assertThat(actual).isEqualTo(new Host(expectedIp, expectedPort));
-    }
-
-    @Test
-    public void parseConfStringShouldParseConfWithHostanmeAndPort() {
-        int expectedPort = 44;
-        String host = "host";
-
-        Host actual = Host.parseConfString(host + ":" + expectedPort);
-
-        assertThat(actual).isEqualTo(new Host(host, expectedPort));
-    }
-
-    @Test
-    public void parseConfStringShouldParseConfWithHostOnlyWhenDefaultPortIsProvided() {
-        //Given
-        String ipAndPort = "142.145.254.111";
-        String expectedIp = "142.145.254.111";
-
-        //When
-        Host actual = Host.parseConfString(ipAndPort, DEFAULT_PORT);
-
-        //Then
-        assertThat(actual).isEqualTo(new Host(expectedIp, DEFAULT_PORT));
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenConfigIsAnEmptyString() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        //Given
-        String ipAndPort = "";
-
-        //When
-        Host.parseConfString(ipAndPort);
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenOnlyHostnameAndNoDefaultPort() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        //Given
-        String hostname = "hostnameOnly";
-
-        //When
-        Host.parseConfString(hostname);
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenNegativePort() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        Host.parseConfString("host:-1");
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenZeroPort() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        Host.parseConfString("host:0");
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenTooHighPort() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        Host.parseConfString("host:65536");
-    }
-
-    @Test
-    public void parseConfStringShouldFailWhenConfigIsANullString() {
-        expectedException.expect(NullPointerException.class);
-
-        //Given
-        String ipAndPort = null;
-
-        //When
-        Host.parseConfString(ipAndPort);
-    }
-
-
-    @Test
-    public void parseConfStringShouldFailWhenConfigIsInvalid() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        //Given
-        String ipAndPort = "10.10.10.10:42:43";
-
-        //When
-        Host.parseConfString(ipAndPort);
-    }
-
-    @Test
-    public void parseHostsShouldParseEmptyString() {
-        assertThat(Host.parseHosts(""))
-            .isEmpty();
-    }
-
-    @Test
-    public void parseHostsShouldParseMonoHost() {
-        assertThat(Host.parseHosts("localhost:9200"))
-            .containsOnly(new Host("localhost", 9200));
-    }
-
-    @Test
-    public void parseHostsShouldParseMultiHosts() {
-        assertThat(Host.parseHosts("localhost:9200,server:9155"))
-            .containsOnly(
-                new Host("localhost", 9200),
-                new Host("server", 9155));
-    }
-
-    @Test
-    public void parseHostsShouldNotFailOnMultiComma() {
-        assertThat(Host.parseHosts("localhost:9200,,server:9155"))
-            .containsOnly(
-                new Host("localhost", 9200),
-                new Host("server", 9155));
-    }
-
-    @Test
-    public void parseHostsShouldFailOnInvalidHost() {
-        expectedException.expect(NumberFormatException.class);
-
-        Host.parseHosts("localhost:invalid,,server:9155");
-    }
-
-    @Test
-    public void parseHostsShouldSwallowDuplicates() {
-        assertThat(Host.parseHosts("localhost:9200,localhost:9200"))
-            .containsOnly(
-                new Host("localhost", 9200));
-    }
-
-    @Test
-    public void parseHostsShouldNotSwallowSameAddressDifferentPort() {
-        assertThat(Host.parseHosts("localhost:9200,localhost:9155"))
-            .containsOnly(
-                new Host("localhost", 9200),
-                new Host("localhost", 9155));
-    }
-
-    @Test
-    public void parseHostsShouldNotSwallowSamePortDifferentAddress() {
-        assertThat(Host.parseHosts("localhost:9200,abcd:9200"))
-            .containsOnly(
-                new Host("localhost", 9200),
-                new Host("abcd", 9200));
-    }
-
-    @Test
-    public void parseHostsShouldHandleDefaultPort() {
-        int defaultPort = 155;
-
-        assertThat(Host.parseHosts("localhost:9200,abcd", defaultPort))
-            .containsOnly(
-                new Host("localhost", 9200),
-                new Host("abcd", 155));
-    }
-
-    @Test
-    public void parseHostsShouldThrowOnAbsentPortWhenNoDefaultPort() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        Host.parseHosts("localhost:9200,abcd");
-    }
-
-    @Test
-    public void hostShouldRespectBeanContract() {
-        EqualsVerifier.forClass(Host.class).verify();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/MDCBuilderTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/MDCBuilderTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/MDCBuilderTest.java
deleted file mode 100644
index d8ac33c..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/MDCBuilderTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
-
-public class MDCBuilderTest {
-
-    private static final String KEY_1 = "key1";
-    private static final String KEY_2 = "key2";
-    private static final String VALUE_1 = "value1";
-    private static final String VALUE_2 = "value2";
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void addContextShouldThrowOnNullKey() {
-        expectedException.expect(NullPointerException.class);
-
-        MDCBuilder.create()
-            .addContext(null, "any");
-    }
-
-    @Test
-    public void buildContextMapShouldReturnEmptyWhenNoContext() {
-        assertThat(MDCBuilder.create().buildContextMap())
-            .isEmpty();
-    }
-
-    @Test
-    public void buildContextMapShouldReturnContext() {
-        assertThat(
-            MDCBuilder.create()
-                .addContext(KEY_1, VALUE_1)
-                .addContext(KEY_2, VALUE_2)
-                .buildContextMap())
-            .containsOnlyKeys(KEY_1, KEY_2)
-            .containsEntry(KEY_1, VALUE_1)
-            .containsEntry(KEY_2, VALUE_2);
-    }
-
-    @Test
-    public void addContextShouldFilterOutNullValues() {
-        assertThat(
-            MDCBuilder.create()
-                .addContext(KEY_1, null)
-                .buildContextMap())
-            .isEmpty();
-    }
-
-    @Test
-    public void addContextShouldAllowRecursiveBuild() {
-        assertThat(
-            MDCBuilder.create()
-                .addContext(KEY_1, VALUE_1)
-                .addContext(MDCBuilder.create()
-                    .addContext(KEY_2, VALUE_2))
-                .buildContextMap())
-            .containsOnlyKeys(KEY_1, KEY_2)
-            .containsEntry(KEY_1, VALUE_1)
-            .containsEntry(KEY_2, VALUE_2);
-    }
-
-    @SuppressWarnings("resource")
-    @Test
-    public void closeablesConstructorShouldThrowOnNullList() {
-        expectedException.expect(NullPointerException.class);
-
-        new MDCBuilder.Closeables(null);
-    }
-
-    @Test
-    public void closeablesCloseShouldNotThrowWhenEmpty() throws IOException {
-        new MDCBuilder.Closeables(ImmutableList.of())
-            .close();
-    }
-
-    @Test
-    public void closeablesCloseShouldCallAllUnderlyingCloseables() throws IOException {
-        ImmutableList.Builder<String> builder = ImmutableList.builder();
-
-        Closeable closeable1 = () -> builder.add(VALUE_1);
-        Closeable closeable2 = () -> builder.add(VALUE_2);
-
-        new MDCBuilder.Closeables(
-            ImmutableList.of(closeable1, closeable2))
-            .close();
-
-        assertThat(builder.build())
-            .containsExactly(VALUE_1, VALUE_2);
-    }
-
-
-    @Test
-    public void closeablesCloseShouldCallAllUnderlyingCloseablesWhenError() throws IOException {
-        ImmutableList.Builder<String> builder = ImmutableList.builder();
-
-        Closeable closeable1 = () -> builder.add(VALUE_1);
-        Closeable closeable2 = () -> {
-            throw new IOException();
-        };
-        Closeable closeable3 = () -> builder.add(VALUE_2);
-
-        new MDCBuilder.Closeables(
-            ImmutableList.of(closeable1, closeable2, closeable3))
-            .close();
-
-        assertThat(builder.build())
-            .containsExactly(VALUE_1, VALUE_2);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/MemoizedSupplierTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
deleted file mode 100644
index e774354..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Supplier;
-
-import org.junit.Test;
-
-public class MemoizedSupplierTest {
-
-    @Test
-    public void getShouldReturnSuppliedValue() {
-        Supplier<Integer> supplier = MemoizedSupplier.of(() -> 42);
-
-        assertThat(supplier.get()).isEqualTo(42);
-    }
-
-    @Test
-    public void getShouldBeIdempotent() {
-        Supplier<Integer> supplier = MemoizedSupplier.of(() -> 42);
-
-        supplier.get();
-        assertThat(supplier.get()).isEqualTo(42);
-    }
-
-    @Test
-    public void nullValueShouldBeSupported() {
-        Supplier<Integer> supplier = MemoizedSupplier.of(() -> null);
-
-        supplier.get();
-        assertThat(supplier.get()).isNull();
-    }
-
-    @Test
-    public void underlyingSupplierShouldBeCalledOnlyOnce() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-
-        Supplier<Integer> supplier = MemoizedSupplier.of(() -> {
-            atomicInteger.incrementAndGet();
-            return 42;
-        });
-
-        supplier.get();
-        supplier.get();
-
-        assertThat(atomicInteger.get()).isEqualTo(1);
-    }
-
-    @Test
-    public void underlyingSupplierShouldBeCalledOnlyOnceWhenReturningNullValue() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-
-        Supplier<Integer> supplier = MemoizedSupplier.of(() -> {
-            atomicInteger.incrementAndGet();
-            return null;
-        });
-
-        supplier.get();
-        supplier.get();
-
-        assertThat(atomicInteger.get()).isEqualTo(1);
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
deleted file mode 100644
index 17fe06e..0000000
--- a/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import com.github.steveash.guavate.Guavate;
-
-public class OptionalUtilsTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void ifEmptyShouldPreserveValueOfEmptyOptionals() {
-        Optional<Object> expected = OptionalUtils.executeIfEmpty(Optional.empty(), () -> { });
-
-        assertThat(expected).isEmpty();
-    }
-
-    @Test
-    public void ifEmptyShouldPreserveValueOfPresentOptionals() {
-        String value = "value";
-        Optional<String> expected = OptionalUtils.executeIfEmpty(Optional.of(value), () -> { });
-
-        assertThat(expected).contains(value);
-    }
-
-    @Test
-    public void ifEmptyShouldPerformOperationIfEmpty() {
-        AtomicInteger operationCounter = new AtomicInteger(0);
-
-        OptionalUtils.executeIfEmpty(Optional.empty(), operationCounter::incrementAndGet);
-
-        assertThat(operationCounter.get()).isEqualTo(1);
-    }
-
-    @Test
-    public void ifEmptyShouldNotPerformOperationIfPresent() {
-        AtomicInteger operationCounter = new AtomicInteger(0);
-
-        OptionalUtils.executeIfEmpty(Optional.of("value"), operationCounter::incrementAndGet);
-
-        assertThat(operationCounter.get()).isEqualTo(0);
-    }
-
-    @Test
-    public void toStreamShouldConvertEmptyOptionalToEmptyStream() {
-        assertThat(
-            OptionalUtils.toStream(Optional.empty())
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    public void toStreamShouldConvertFullOptionalToStream() {
-        long value = 18L;
-        assertThat(
-            OptionalUtils.toStream(Optional.of(value))
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(value);
-    }
-
-    @Test
-    public void orShouldReturnEmptyWhenNoParameter() {
-        assertThat(OptionalUtils.or())
-            .isEmpty();
-    }
-
-    @Test
-    public void orShouldReturnEmptyWhenEmpty() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.empty()))
-            .isEmpty();
-    }
-
-    @Test
-    public void orShouldReturnValueWhenValue() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.of(1)))
-            .contains(1);
-    }
-
-    @Test
-    public void orShouldReturnEmptyWhenBothEmpty() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.empty(),
-                Optional.empty()))
-            .isEmpty();
-    }
-
-    @Test
-    public void orShouldReturnFirstValueWhenOnlyFirstValue() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.of(18),
-                Optional.empty()))
-            .contains(18);
-    }
-
-    @Test
-    public void orShouldReturnSecondValueWhenOnlySecondValue() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.empty(),
-                Optional.of(18)))
-            .contains(18);
-    }
-
-    @Test
-    public void orShouldReturnFirstValueWhenBothValues() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.of(1),
-                Optional.of(2)))
-            .contains(1);
-    }
-
-    @Test
-    public void orShouldReturnThirdValueWhenOnlyThirdValue() {
-        assertThat(
-            OptionalUtils.or(
-                Optional.empty(),
-                Optional.empty(),
-                Optional.of(1)))
-            .contains(1);
-    }
-
-    @Test
-    public void orSuppliersShouldReturnEmptyWhenNoParameter() {
-        assertThat(OptionalUtils.or())
-            .isEmpty();
-    }
-
-    @Test
-    public void orSuppliersShouldReturnEmptyWhenEmpty() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                Optional::empty))
-            .isEmpty();
-    }
-
-    @Test
-    public void orSuppliersShouldReturnValueWhenValue() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                () -> Optional.of(1)))
-            .contains(1);
-    }
-
-    @Test
-    public void orSuppliersShouldReturnEmptyWhenBothEmpty() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                () -> Optional.empty(),
-                () -> Optional.empty()))
-            .isEmpty();
-    }
-
-    @Test
-    public void orSuppliersShouldReturnFirstValueWhenOnlyFirstValue() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                () -> Optional.of(18),
-                Optional::empty))
-            .contains(18);
-    }
-
-    @Test
-    public void orSuppliersShouldReturnSecondValueWhenOnlySecondValue() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                Optional::empty,
-                () -> Optional.of(18)))
-            .contains(18);
-    }
-
-    @Test
-    public void orSuppliersShouldReturnFirstValueWhenBothValues() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                () -> Optional.of(1),
-                () -> Optional.of(2)))
-            .contains(1);
-    }
-
-    @Test
-    public void orSuppliersShouldReturnThirdValueWhenOnlyThirdValue() {
-        assertThat(
-            OptionalUtils.orSuppliers(
-                Optional::empty,
-                Optional::empty,
-                () -> Optional.of(1)))
-            .contains(1);
-    }
-
-    @Test
-    public void containsDifferentShouldReturnTrueWhenNullStoreValue() throws Exception {
-        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), null)).isTrue();
-    }
-
-    @Test
-    public void containsDifferentShouldReturnFalseWhenEmpty() throws Exception {
-        assertThat(OptionalUtils.containsDifferent(Optional.empty(), "any")).isFalse();
-    }
-
-    @Test
-    public void containsDifferentShouldReturnFalseWhenSameValue() throws Exception {
-        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), "any")).isFalse();
-    }
-
-    @Test
-    public void containsDifferentShouldReturnTrueWhenDifferentValue() throws Exception {
-        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), "other")).isTrue();
-    }
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[02/14] james-project git commit: JAMES-2502 fix Eclipse Photon build for dnsservice

Posted by ma...@apache.org.
JAMES-2502 fix Eclipse Photon build for dnsservice


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/136acc1e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/136acc1e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/136acc1e

Branch: refs/heads/master
Commit: 136acc1e9cc0f80d8e2f947eb37199fa1867759e
Parents: 3dddd7c
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Fri Jul 27 18:18:22 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:20:23 2018 +0200

----------------------------------------------------------------------
 mpt/impl/smtp/core/pom.xml                      |   3 +-
 pom.xml                                         |   5 +
 server/data/data-cassandra/pom.xml              |   3 +-
 server/data/data-file/pom.xml                   |   3 +-
 server/data/data-hbase/pom.xml                  |   3 +-
 server/data/data-jpa/pom.xml                    |   3 +-
 server/data/data-library/pom.xml                |   3 +-
 server/data/data-memory/pom.xml                 |   3 +-
 .../dnsservice/api/AbstractDNSServiceTest.java  |  94 ------------
 .../dnsservice/api/InMemoryDNSService.java      | 146 -------------------
 .../james/dnsservice/api/mock/DNSFixture.java   |  97 ------------
 .../dnsservice/api/mock/MockDNSService.java     |  61 --------
 server/dns-service/dnsservice-library/pom.xml   |   3 +-
 server/dns-service/dnsservice-test/pom.xml      |  72 +++++++++
 .../dnsservice/api/AbstractDNSServiceTest.java  |  94 ++++++++++++
 .../dnsservice/api/InMemoryDNSService.java      | 146 +++++++++++++++++++
 .../james/dnsservice/api/mock/DNSFixture.java   |  97 ++++++++++++
 .../dnsservice/api/mock/MockDNSService.java     |  61 ++++++++
 server/mailet/integration-testing/pom.xml       |   3 +-
 server/mailet/mailets/pom.xml                   |   3 +-
 server/pom.xml                                  |   1 +
 .../cassandra-jmap-integration-testing/pom.xml  |   3 +-
 .../jmap-integration-testing-common/pom.xml     |   3 +-
 .../memory-jmap-integration-testing/pom.xml     |   3 +-
 server/protocols/protocols-smtp/pom.xml         |   3 +-
 .../protocols/webadmin/webadmin-mailbox/pom.xml |   3 +-
 26 files changed, 491 insertions(+), 428 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/mpt/impl/smtp/core/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/smtp/core/pom.xml b/mpt/impl/smtp/core/pom.xml
index 18174b0..045de64 100644
--- a/mpt/impl/smtp/core/pom.xml
+++ b/mpt/impl/smtp/core/pom.xml
@@ -42,11 +42,10 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
+            <artifactId>james-server-dnsservice-test</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 669d927..2007c5f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1242,6 +1242,11 @@
             </dependency>
             <dependency>
                 <groupId>${james.groupId}</groupId>
+                <artifactId>james-server-dnsservice-test</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${james.groupId}</groupId>
                 <artifactId>james-server-fetchmail</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/pom.xml b/server/data/data-cassandra/pom.xml
index f7b575e..2e3eb96 100644
--- a/server/data/data-cassandra/pom.xml
+++ b/server/data/data-cassandra/pom.xml
@@ -77,8 +77,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-file/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-file/pom.xml b/server/data/data-file/pom.xml
index 16c3abd..6c9dfd9 100644
--- a/server/data/data-file/pom.xml
+++ b/server/data/data-file/pom.xml
@@ -61,8 +61,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-hbase/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-hbase/pom.xml b/server/data/data-hbase/pom.xml
index fd9adca..239ceaa 100644
--- a/server/data/data-hbase/pom.xml
+++ b/server/data/data-hbase/pom.xml
@@ -57,8 +57,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-jpa/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-jpa/pom.xml b/server/data/data-jpa/pom.xml
index c623347..cb0cd25 100644
--- a/server/data/data-jpa/pom.xml
+++ b/server/data/data-jpa/pom.xml
@@ -69,8 +69,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-library/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-library/pom.xml b/server/data/data-library/pom.xml
index 6c7cf0f..8b18787 100644
--- a/server/data/data-library/pom.xml
+++ b/server/data/data-library/pom.xml
@@ -62,8 +62,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/data/data-memory/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-memory/pom.xml b/server/data/data-memory/pom.xml
index b3d7017..b2f2b5a 100644
--- a/server/data/data-memory/pom.xml
+++ b/server/data/data-memory/pom.xml
@@ -60,8 +60,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java b/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
deleted file mode 100644
index edcba79..0000000
--- a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************
- * 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.dnsservice.api;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-
-import org.apache.james.dnsservice.api.mock.MockDNSService;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-
-/**
- * Basic tests for AbstractDNSServer. The goal is to verify that the interface
- * remains constants and that the built platform has access to the Internet.
- */
-public class AbstractDNSServiceTest {
-
-    /**
-     * Simple Mock DNSService relaying on InetAddress.
-     */
-    private static final DNSService DNS_SERVER = new MockDNSService() {
-
-        @Override
-        public String getHostName(InetAddress inet) {
-            return inet.getCanonicalHostName();
-        }
-
-        @Override
-        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
-            return ImmutableList.copyOf(InetAddress.getAllByName(name));
-        }
-
-        @Override
-        public InetAddress getLocalHost() throws UnknownHostException {
-            return InetAddress.getLocalHost();
-        }
-
-        @Override
-        public InetAddress getByName(String host) throws UnknownHostException {
-            return InetAddress.getByName(host);
-        }
-    };
-
-    /**
-     * Simple localhost resolution.
-     *
-     * @throws UnknownHostException
-     */
-    @Test
-    public void testLocalhost() throws UnknownHostException {
-
-        assertEquals("localhost/127.0.0.1", DNS_SERVER.getByName("localhost").toString());
-
-        String localHost = DNS_SERVER.getHostName(InetAddress.getByName("127.0.0.1"));
-        // We only can check if the returned localhost is not empty. Its value
-        // depends on the hosts file.
-        assertTrue(localHost.length() > 0);
-    }
-
-    /**
-     * Simple apache.org resolution.
-     *
-     * @throws UnknownHostException
-     */
-    @Test
-    @Ignore(value = "It requires internet connection!")
-    public void testApache() throws UnknownHostException {
-        //TODO: move to some sort of Live tests
-        assertEquals(true, DNS_SERVER.getByName("www.apache.org").toString().startsWith("www.apache.org"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/InMemoryDNSService.java b/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
deleted file mode 100644
index 76f1148..0000000
--- a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************
- * 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.dnsservice.api;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.function.Predicate;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.google.common.net.InetAddresses;
-
-public class InMemoryDNSService implements DNSService {
-
-    private Map<String,DNSRecord> records;
-
-    public InMemoryDNSService() {
-        records = Maps.newHashMap();
-        records.put("0.0.0.0", dnsRecordFor(InetAddresses.forString("0.0.0.0")));
-        records.put("127.0.0.1", dnsRecordFor(InetAddresses.forString("127.0.0.1")));
-    }
-
-    private DNSRecord dnsRecordFor(InetAddress addresses) {
-        Collection<String> emptyList = ImmutableList.of();
-        return dnsRecordFor(emptyList, emptyList, ImmutableList.of(addresses));
-    }
-
-    private DNSRecord dnsRecordFor(Collection<String> mxRecords, Collection<String> txtRecords, List<InetAddress> addresses) {
-        return new DNSRecord(addresses, mxRecords, txtRecords);
-    }
-
-    public InMemoryDNSService registerRecord(String hostname, InetAddress address, String mxRecord) {
-        Collection<String> emptyTxtRecords = ImmutableList.of();
-        registerRecord(hostname, ImmutableList.of(address), ImmutableList.of(mxRecord), emptyTxtRecords);
-        return this;
-    }
-
-    public InMemoryDNSService registerMxRecord(String hostname, String ip) throws UnknownHostException {
-        InetAddress containerIp = InetAddress.getByName(ip);
-        registerRecord(hostname, containerIp, hostname);
-        return this;
-    }
-
-    public InMemoryDNSService registerRecord(String hostname, List<InetAddress> addresses, Collection<String> mxRecords, Collection<String> txtRecords) {
-        records.put(hostname, dnsRecordFor(mxRecords, txtRecords, addresses));
-        return this;
-    }
-
-    public void dropRecord(String hostname) {
-        records.remove(hostname);
-    }
-
-    @Override
-    public Collection<String> findMXRecords(String hostname) throws TemporaryResolutionException {
-        try {
-            return hostRecord(hostname).mxRecords;
-        } catch (UnknownHostException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public Collection<String> findTXTRecords(String hostname) {
-        try {
-            return hostRecord(hostname).txtRecords;
-        } catch (UnknownHostException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public List<InetAddress> getAllByName(String host) throws UnknownHostException {
-        return hostRecord(host).addresses;
-    }
-
-    @Override
-    public InetAddress getByName(String host) throws UnknownHostException {
-        return hostRecord(host).addresses.get(0);
-    }
-
-    private DNSRecord hostRecord(final String host) throws UnknownHostException {
-        Predicate<? super Entry<String, DNSRecord>> filterByKey = entry -> entry.getKey().equals(host);
-        return getDNSEntry(filterByKey).getValue();
-    }
-
-    @Override
-    public InetAddress getLocalHost() throws UnknownHostException {
-        return InetAddress.getLocalHost();
-    }
-
-    @Override
-    public String getHostName(final InetAddress addr) {
-        Predicate<? super Entry<String, DNSRecord>> filterByValue = entry -> entry.getValue().contains(addr);
-
-        try {
-            return getDNSEntry(filterByValue).getKey();
-        } catch (UnknownHostException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private Entry<String, DNSRecord> getDNSEntry(Predicate<? super Entry<String, DNSRecord>> filter) throws UnknownHostException {
-        return records.entrySet().stream()
-            .filter(filter)
-            .findFirst()
-            .orElseThrow(() -> new UnknownHostException());
-    }
-
-    public static class DNSRecord {
-
-        final Collection<String> mxRecords;
-        final Collection<String> txtRecords;
-        private final List<InetAddress> addresses;
-
-        public DNSRecord(List<InetAddress> addresses, Collection<String> mxRecords, Collection<String> txtRecords) {
-            this.addresses = addresses;
-            this.mxRecords = mxRecords;
-            this.txtRecords = txtRecords;
-        }
-
-        public boolean contains(InetAddress address) {
-            return addresses.contains(address);
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/DNSFixture.java b/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
deleted file mode 100644
index bd91def..0000000
--- a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/****************************************************************
- * 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.dnsservice.api.mock;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-
-import org.apache.james.dnsservice.api.DNSService;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Some DNS Fixtures used by various Test related to DNS and InetNetwork.
- */
-public class DNSFixture {
-
-    public static final String LOCALHOST_IP_V4_ADDRESS_0 = "localhost/16";
-    public static final String LOCALHOST_IP_V4_ADDRESS_1 = "172.16.0.0/16";
-    public static final String LOCALHOST_IP_V4_ADDRESS_2 = "192.168.1.0/255.255.255.0";
-    public static final String[] LOCALHOST_IP_V4_ADDRESSES = new String[]{LOCALHOST_IP_V4_ADDRESS_0,
-        LOCALHOST_IP_V4_ADDRESS_1, LOCALHOST_IP_V4_ADDRESS_2};
-    public static final String[] LOCALHOST_IP_V4_ADDRESSES_DUPLICATE = new String[]{LOCALHOST_IP_V4_ADDRESS_1,
-        LOCALHOST_IP_V4_ADDRESS_1, LOCALHOST_IP_V4_ADDRESS_2, LOCALHOST_IP_V4_ADDRESS_2};
-    public static final String LOCALHOST_IP_V6_ADDRESS_0 = "00:00:00:00:00:00:00:1";
-    public static final String LOCALHOST_IP_V6_ADDRESS_1 = "2781:0db8:1234:8612:45ee:0000:f05e:0001/48";
-    public static final String[] LOCALHOST_IP_V6_ADDRESSES = new String[]{LOCALHOST_IP_V6_ADDRESS_0,
-        LOCALHOST_IP_V6_ADDRESS_1};
-    public static final String[] LOCALHOST_IP_V6_ADDRESSES_DUPLICATE = new String[]{LOCALHOST_IP_V6_ADDRESS_0,
-        LOCALHOST_IP_V6_ADDRESS_0, LOCALHOST_IP_V6_ADDRESS_1, LOCALHOST_IP_V6_ADDRESS_1};
-    /**
-     * A Mock DNS Server that handles IPv4-only InetAddress.
-     */
-    public static final DNSService DNS_SERVER_IPV4_MOCK = new MockDNSService() {
-
-        @Override
-        public String getHostName(InetAddress inet) {
-            return "localhost";
-        }
-
-        @Override
-        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
-            return ImmutableList.of(InetAddress.getByName("127.0.0.1"));
-        }
-
-        @Override
-        public InetAddress getLocalHost() throws UnknownHostException {
-            return InetAddress.getLocalHost();
-        }
-
-        @Override
-        public InetAddress getByName(String host) throws UnknownHostException {
-            return InetAddress.getByName(host);
-        }
-    };
-    /**
-     * A Mock DNS Server that handles IPv6-only InetAddress.
-     */
-    public static final DNSService DNS_SERVER_IPV6_MOCK = new MockDNSService() {
-
-        @Override
-        public String getHostName(InetAddress inet) {
-            return "localhost";
-        }
-
-        @Override
-        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
-            return ImmutableList.of(InetAddress.getByName("::1"));
-        }
-
-        @Override
-        public InetAddress getLocalHost() throws UnknownHostException {
-            return InetAddress.getLocalHost();
-        }
-
-        @Override
-        public InetAddress getByName(String host) throws UnknownHostException {
-            return InetAddress.getByName(host);
-        }
-    };
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/MockDNSService.java b/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
deleted file mode 100644
index b7c238c..0000000
--- a/server/dns-service/dnsservice-api/src/test/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************
- * 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.dnsservice.api.mock;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-
-import org.apache.james.dnsservice.api.DNSService;
-
-/**
- * Abstract class to simplify the mocks
- */
-public class MockDNSService implements DNSService {
-
-    @Override
-    public Collection<String> findMXRecords(String hostname) {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-
-    @Override
-    public Collection<String> findTXTRecords(String hostname) {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-
-    @Override
-    public Collection<InetAddress> getAllByName(String host) throws UnknownHostException {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-
-    @Override
-    public InetAddress getByName(String host) throws UnknownHostException {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-
-    @Override
-    public String getHostName(InetAddress addr) {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-
-    @Override
-    public InetAddress getLocalHost() throws UnknownHostException {
-        throw new UnsupportedOperationException("Unimplemented Stub Method");
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-library/pom.xml
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-library/pom.xml b/server/dns-service/dnsservice-library/pom.xml
index 1155ede..cf4a9cf 100644
--- a/server/dns-service/dnsservice-library/pom.xml
+++ b/server/dns-service/dnsservice-library/pom.xml
@@ -43,8 +43,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-test/pom.xml
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-test/pom.xml b/server/dns-service/dnsservice-test/pom.xml
new file mode 100644
index 0000000..2b203db
--- /dev/null
+++ b/server/dns-service/dnsservice-test/pom.xml
@@ -0,0 +1,72 @@
+<?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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>james-server</artifactId>
+        <version>3.2.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>james-server-dnsservice-test</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache James :: Server :: DNS Service :: Test</name>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-dnsservice-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
new file mode 100644
index 0000000..edcba79
--- /dev/null
+++ b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/AbstractDNSServiceTest.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * 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.dnsservice.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+
+import org.apache.james.dnsservice.api.mock.MockDNSService;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+
+/**
+ * Basic tests for AbstractDNSServer. The goal is to verify that the interface
+ * remains constants and that the built platform has access to the Internet.
+ */
+public class AbstractDNSServiceTest {
+
+    /**
+     * Simple Mock DNSService relaying on InetAddress.
+     */
+    private static final DNSService DNS_SERVER = new MockDNSService() {
+
+        @Override
+        public String getHostName(InetAddress inet) {
+            return inet.getCanonicalHostName();
+        }
+
+        @Override
+        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
+            return ImmutableList.copyOf(InetAddress.getAllByName(name));
+        }
+
+        @Override
+        public InetAddress getLocalHost() throws UnknownHostException {
+            return InetAddress.getLocalHost();
+        }
+
+        @Override
+        public InetAddress getByName(String host) throws UnknownHostException {
+            return InetAddress.getByName(host);
+        }
+    };
+
+    /**
+     * Simple localhost resolution.
+     *
+     * @throws UnknownHostException
+     */
+    @Test
+    public void testLocalhost() throws UnknownHostException {
+
+        assertEquals("localhost/127.0.0.1", DNS_SERVER.getByName("localhost").toString());
+
+        String localHost = DNS_SERVER.getHostName(InetAddress.getByName("127.0.0.1"));
+        // We only can check if the returned localhost is not empty. Its value
+        // depends on the hosts file.
+        assertTrue(localHost.length() > 0);
+    }
+
+    /**
+     * Simple apache.org resolution.
+     *
+     * @throws UnknownHostException
+     */
+    @Test
+    @Ignore(value = "It requires internet connection!")
+    public void testApache() throws UnknownHostException {
+        //TODO: move to some sort of Live tests
+        assertEquals(true, DNS_SERVER.getByName("www.apache.org").toString().startsWith("www.apache.org"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/InMemoryDNSService.java b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
new file mode 100644
index 0000000..76f1148
--- /dev/null
+++ b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/InMemoryDNSService.java
@@ -0,0 +1,146 @@
+/****************************************************************
+ * 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.dnsservice.api;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Predicate;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.common.net.InetAddresses;
+
+public class InMemoryDNSService implements DNSService {
+
+    private Map<String,DNSRecord> records;
+
+    public InMemoryDNSService() {
+        records = Maps.newHashMap();
+        records.put("0.0.0.0", dnsRecordFor(InetAddresses.forString("0.0.0.0")));
+        records.put("127.0.0.1", dnsRecordFor(InetAddresses.forString("127.0.0.1")));
+    }
+
+    private DNSRecord dnsRecordFor(InetAddress addresses) {
+        Collection<String> emptyList = ImmutableList.of();
+        return dnsRecordFor(emptyList, emptyList, ImmutableList.of(addresses));
+    }
+
+    private DNSRecord dnsRecordFor(Collection<String> mxRecords, Collection<String> txtRecords, List<InetAddress> addresses) {
+        return new DNSRecord(addresses, mxRecords, txtRecords);
+    }
+
+    public InMemoryDNSService registerRecord(String hostname, InetAddress address, String mxRecord) {
+        Collection<String> emptyTxtRecords = ImmutableList.of();
+        registerRecord(hostname, ImmutableList.of(address), ImmutableList.of(mxRecord), emptyTxtRecords);
+        return this;
+    }
+
+    public InMemoryDNSService registerMxRecord(String hostname, String ip) throws UnknownHostException {
+        InetAddress containerIp = InetAddress.getByName(ip);
+        registerRecord(hostname, containerIp, hostname);
+        return this;
+    }
+
+    public InMemoryDNSService registerRecord(String hostname, List<InetAddress> addresses, Collection<String> mxRecords, Collection<String> txtRecords) {
+        records.put(hostname, dnsRecordFor(mxRecords, txtRecords, addresses));
+        return this;
+    }
+
+    public void dropRecord(String hostname) {
+        records.remove(hostname);
+    }
+
+    @Override
+    public Collection<String> findMXRecords(String hostname) throws TemporaryResolutionException {
+        try {
+            return hostRecord(hostname).mxRecords;
+        } catch (UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Collection<String> findTXTRecords(String hostname) {
+        try {
+            return hostRecord(hostname).txtRecords;
+        } catch (UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<InetAddress> getAllByName(String host) throws UnknownHostException {
+        return hostRecord(host).addresses;
+    }
+
+    @Override
+    public InetAddress getByName(String host) throws UnknownHostException {
+        return hostRecord(host).addresses.get(0);
+    }
+
+    private DNSRecord hostRecord(final String host) throws UnknownHostException {
+        Predicate<? super Entry<String, DNSRecord>> filterByKey = entry -> entry.getKey().equals(host);
+        return getDNSEntry(filterByKey).getValue();
+    }
+
+    @Override
+    public InetAddress getLocalHost() throws UnknownHostException {
+        return InetAddress.getLocalHost();
+    }
+
+    @Override
+    public String getHostName(final InetAddress addr) {
+        Predicate<? super Entry<String, DNSRecord>> filterByValue = entry -> entry.getValue().contains(addr);
+
+        try {
+            return getDNSEntry(filterByValue).getKey();
+        } catch (UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private Entry<String, DNSRecord> getDNSEntry(Predicate<? super Entry<String, DNSRecord>> filter) throws UnknownHostException {
+        return records.entrySet().stream()
+            .filter(filter)
+            .findFirst()
+            .orElseThrow(() -> new UnknownHostException());
+    }
+
+    public static class DNSRecord {
+
+        final Collection<String> mxRecords;
+        final Collection<String> txtRecords;
+        private final List<InetAddress> addresses;
+
+        public DNSRecord(List<InetAddress> addresses, Collection<String> mxRecords, Collection<String> txtRecords) {
+            this.addresses = addresses;
+            this.mxRecords = mxRecords;
+            this.txtRecords = txtRecords;
+        }
+
+        public boolean contains(InetAddress address) {
+            return addresses.contains(address);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/DNSFixture.java b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
new file mode 100644
index 0000000..bd91def
--- /dev/null
+++ b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/DNSFixture.java
@@ -0,0 +1,97 @@
+/****************************************************************
+ * 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.dnsservice.api.mock;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+
+import org.apache.james.dnsservice.api.DNSService;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Some DNS Fixtures used by various Test related to DNS and InetNetwork.
+ */
+public class DNSFixture {
+
+    public static final String LOCALHOST_IP_V4_ADDRESS_0 = "localhost/16";
+    public static final String LOCALHOST_IP_V4_ADDRESS_1 = "172.16.0.0/16";
+    public static final String LOCALHOST_IP_V4_ADDRESS_2 = "192.168.1.0/255.255.255.0";
+    public static final String[] LOCALHOST_IP_V4_ADDRESSES = new String[]{LOCALHOST_IP_V4_ADDRESS_0,
+        LOCALHOST_IP_V4_ADDRESS_1, LOCALHOST_IP_V4_ADDRESS_2};
+    public static final String[] LOCALHOST_IP_V4_ADDRESSES_DUPLICATE = new String[]{LOCALHOST_IP_V4_ADDRESS_1,
+        LOCALHOST_IP_V4_ADDRESS_1, LOCALHOST_IP_V4_ADDRESS_2, LOCALHOST_IP_V4_ADDRESS_2};
+    public static final String LOCALHOST_IP_V6_ADDRESS_0 = "00:00:00:00:00:00:00:1";
+    public static final String LOCALHOST_IP_V6_ADDRESS_1 = "2781:0db8:1234:8612:45ee:0000:f05e:0001/48";
+    public static final String[] LOCALHOST_IP_V6_ADDRESSES = new String[]{LOCALHOST_IP_V6_ADDRESS_0,
+        LOCALHOST_IP_V6_ADDRESS_1};
+    public static final String[] LOCALHOST_IP_V6_ADDRESSES_DUPLICATE = new String[]{LOCALHOST_IP_V6_ADDRESS_0,
+        LOCALHOST_IP_V6_ADDRESS_0, LOCALHOST_IP_V6_ADDRESS_1, LOCALHOST_IP_V6_ADDRESS_1};
+    /**
+     * A Mock DNS Server that handles IPv4-only InetAddress.
+     */
+    public static final DNSService DNS_SERVER_IPV4_MOCK = new MockDNSService() {
+
+        @Override
+        public String getHostName(InetAddress inet) {
+            return "localhost";
+        }
+
+        @Override
+        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
+            return ImmutableList.of(InetAddress.getByName("127.0.0.1"));
+        }
+
+        @Override
+        public InetAddress getLocalHost() throws UnknownHostException {
+            return InetAddress.getLocalHost();
+        }
+
+        @Override
+        public InetAddress getByName(String host) throws UnknownHostException {
+            return InetAddress.getByName(host);
+        }
+    };
+    /**
+     * A Mock DNS Server that handles IPv6-only InetAddress.
+     */
+    public static final DNSService DNS_SERVER_IPV6_MOCK = new MockDNSService() {
+
+        @Override
+        public String getHostName(InetAddress inet) {
+            return "localhost";
+        }
+
+        @Override
+        public Collection<InetAddress> getAllByName(String name) throws UnknownHostException {
+            return ImmutableList.of(InetAddress.getByName("::1"));
+        }
+
+        @Override
+        public InetAddress getLocalHost() throws UnknownHostException {
+            return InetAddress.getLocalHost();
+        }
+
+        @Override
+        public InetAddress getByName(String host) throws UnknownHostException {
+            return InetAddress.getByName(host);
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
----------------------------------------------------------------------
diff --git a/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/MockDNSService.java b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
new file mode 100644
index 0000000..b7c238c
--- /dev/null
+++ b/server/dns-service/dnsservice-test/src/main/java/org/apache/james/dnsservice/api/mock/MockDNSService.java
@@ -0,0 +1,61 @@
+/****************************************************************
+ * 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.dnsservice.api.mock;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+
+import org.apache.james.dnsservice.api.DNSService;
+
+/**
+ * Abstract class to simplify the mocks
+ */
+public class MockDNSService implements DNSService {
+
+    @Override
+    public Collection<String> findMXRecords(String hostname) {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public Collection<String> findTXTRecords(String hostname) {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public Collection<InetAddress> getAllByName(String host) throws UnknownHostException {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public InetAddress getByName(String host) throws UnknownHostException {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public String getHostName(InetAddress addr) {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public InetAddress getLocalHost() throws UnknownHostException {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/mailet/integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/pom.xml b/server/mailet/integration-testing/pom.xml
index 0af81e4..3a53ffc 100644
--- a/server/mailet/integration-testing/pom.xml
+++ b/server/mailet/integration-testing/pom.xml
@@ -54,8 +54,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/mailet/mailets/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/pom.xml b/server/mailet/mailets/pom.xml
index 5a3f3cc..c199753 100644
--- a/server/mailet/mailets/pom.xml
+++ b/server/mailet/mailets/pom.xml
@@ -138,8 +138,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index 21c6e8a..7b25899 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -71,6 +71,7 @@
         <module>dns-service/dnsservice-api</module>
         <module>dns-service/dnsservice-dnsjava</module>
         <module>dns-service/dnsservice-library</module>
+        <module>dns-service/dnsservice-test</module>
 
         <module>mailet/integration-testing</module>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
index 6309274..0380b9c 100644
--- a/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
+++ b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
@@ -87,8 +87,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
index 7f69759..b109376 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
@@ -51,8 +51,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
index c873e5e..180cab6 100644
--- a/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
+++ b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
@@ -46,8 +46,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/protocols/protocols-smtp/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-smtp/pom.xml b/server/protocols/protocols-smtp/pom.xml
index 9291472..3a4f615 100644
--- a/server/protocols/protocols-smtp/pom.xml
+++ b/server/protocols/protocols-smtp/pom.xml
@@ -93,8 +93,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/136acc1e/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index 0f366a9..5c91f4a 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -35,8 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-dnsservice-api</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[06/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java b/server/container/util/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
new file mode 100644
index 0000000..deae849
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/mime/MessageContentExtractorTest.java
@@ -0,0 +1,514 @@
+/****************************************************************
+ * 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.util.mime;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.dom.Multipart;
+import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.message.BasicBodyFactory;
+import org.apache.james.mime4j.message.BodyPart;
+import org.apache.james.mime4j.message.BodyPartBuilder;
+import org.apache.james.mime4j.message.HeaderImpl;
+import org.apache.james.mime4j.message.MultipartBuilder;
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.util.mime.MessageContentExtractor.MessageContent;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MessageContentExtractorTest {
+    private static final String BINARY_CONTENT = "binary";
+    private static final String TEXT_CONTENT = "text content";
+    private static final String HTML_CONTENT = "<b>html</b> content";
+    private static final String TEXT_CONTENT2 = "other text content";
+    private static final String HTML_CONTENT2 = "other <b>html</b> content";
+    private static final String ATTACHMENT_CONTENT = "attachment content";
+    private static final String ANY_VALUE = "anyValue";
+    private static final Field CONTENT_ID_FIELD = new Field() {
+        @Override
+        public String getName() {
+            return MessageContentExtractor.CONTENT_ID;
+        }
+
+        @Override
+        public String getBody() {
+            return ANY_VALUE;
+        }
+
+        @Override
+        public ByteSequence getRaw() {
+            return ByteSequence.EMPTY;
+        }
+    };
+
+    private MessageContentExtractor testee;
+
+    private BodyPartBuilder htmlPart;
+    private BodyPartBuilder textPart;
+    private BodyPartBuilder textAttachment;
+    private BodyPartBuilder inlineText;
+    private BodyPartBuilder inlineImage;
+
+    @Before
+    public void setup() throws IOException {
+        testee = new MessageContentExtractor();
+        textPart = BodyPartBuilder.create().setBody(TEXT_CONTENT, "plain", StandardCharsets.UTF_8);
+        htmlPart = BodyPartBuilder.create().setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8);
+        textAttachment = BodyPartBuilder.create()
+                .setBody(ATTACHMENT_CONTENT, "plain", StandardCharsets.UTF_8)
+                .setContentDisposition("attachment");
+        inlineText = BodyPartBuilder.create()
+                .setBody(ATTACHMENT_CONTENT, "plain", StandardCharsets.UTF_8)
+                .setContentDisposition("inline");
+        inlineImage = BodyPartBuilder.create()
+                .setBody(new byte[0], "image/png")
+                .setContentDisposition("inline");
+    }
+
+    @Test
+    public void extractShouldReturnEmptyWhenBinaryContentOnly() throws IOException {
+        Message message = Message.Builder.of()
+                .setBody(BasicBodyFactory.INSTANCE.binaryBody(BINARY_CONTENT, StandardCharsets.UTF_8))
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldReturnTextOnlyWhenTextOnlyBody() throws IOException {
+        Message message = Message.Builder.of()
+                .setBody(TEXT_CONTENT, StandardCharsets.UTF_8)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldReturnHtmlOnlyWhenHtmlOnlyBody() throws IOException {
+        Message message = Message.Builder.of()
+                .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnHtmlAndTextWhenMultipartAlternative() throws IOException {
+        Multipart multipart = MultipartBuilder.create("alternative")
+                .addBodyPart(textPart)
+                .addBodyPart(htmlPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnHtmlWhenMultipartAlternativeWithoutPlainPart() throws IOException {
+        Multipart multipart = MultipartBuilder.create("alternative")
+                .addBodyPart(htmlPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnTextWhenMultipartAlternativeWithoutHtmlPart() throws IOException {
+        Multipart multipart = MultipartBuilder.create("alternative")
+                .addBodyPart(textPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldReturnFirstNonAttachmentPartWhenMultipartMixed() throws IOException {
+        Multipart multipart = MultipartBuilder.create("mixed")
+                .addBodyPart(textAttachment)
+                .addBodyPart(htmlPart)
+                .addBodyPart(textPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+        assertThat(actual.getTextBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldReturnInlinedTextBodyWithoutCIDWhenNoOtherValidParts() throws IOException {
+        String textBody = "body 1";
+        Multipart multipart = MultipartBuilder.create("report")
+            .addBodyPart(BodyPartBuilder.create()
+                .setBody(textBody, "plain", StandardCharsets.UTF_8)
+                .setContentDisposition("inline"))
+            .addBodyPart(BodyPartBuilder.create()
+                .setBody("body 2", "rfc822-headers", StandardCharsets.UTF_8)
+                .setContentDisposition("inline"))
+            .build();
+        Message message = Message.Builder.of()
+            .setBody(multipart)
+            .build();
+
+        MessageContent actual = testee.extract(message);
+
+        assertThat(actual.getTextBody()).contains(textBody);
+    }
+
+    @Test
+    public void extractShouldReturnEmptyWhenMultipartMixedAndFirstPartIsATextAttachment() throws IOException {
+        Multipart multipart = MultipartBuilder.create("mixed")
+                .addBodyPart(textAttachment)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldReturnFirstPartOnlyWhenMultipartMixedAndFirstPartIsHtml() throws IOException {
+        Multipart multipart = MultipartBuilder.create("mixed")
+                .addBodyPart(htmlPart)
+                .addBodyPart(textPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnHtmlAndTextWhenMultipartMixedAndFirstPartIsMultipartAlternative() throws IOException {
+        BodyPart multipartAlternative = BodyPartBuilder.create()
+            .setBody(MultipartBuilder.create("alternative")
+                    .addBodyPart(htmlPart)
+                    .addBodyPart(textPart)
+                    .build())
+            .build();
+        Multipart multipartMixed = MultipartBuilder.create("mixed")
+                .addBodyPart(multipartAlternative)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipartMixed)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnHtmlWhenMultipartRelated() throws IOException {
+        Multipart multipart = MultipartBuilder.create("related")
+                .addBodyPart(htmlPart)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipart)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).isEmpty();
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldReturnHtmlAndTextWhenMultipartAlternativeAndFirstPartIsMultipartRelated() throws IOException {
+        BodyPart multipartRelated = BodyPartBuilder.create()
+            .setBody(MultipartBuilder.create("related")
+                    .addBodyPart(htmlPart)
+                    .build())
+            .build();
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+                .addBodyPart(multipartRelated)
+                .build();
+        Message message = Message.Builder.of()
+                .setBody(multipartAlternative)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldRetrieveHtmlBodyWithOneInlinedHTMLAttachmentWithoutCid() throws IOException {
+        //Given
+        BodyPart inlinedHTMLPart = BodyPartBuilder.create()
+            .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
+            .build();
+        HeaderImpl inlinedHeader = new HeaderImpl();
+        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
+        inlinedHeader.addField(Fields.contentType("text/html; charset=utf-8"));
+        inlinedHTMLPart.setHeader(inlinedHeader);
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+            .addBodyPart(inlinedHTMLPart)
+            .build();
+        Message message = Message.Builder.of()
+            .setBody(multipartAlternative)
+            .build();
+
+        //When
+        MessageContent actual = testee.extract(message);
+
+        //Then
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldNotRetrieveHtmlBodyWithOneInlinedHTMLAttachmentWithCid() throws IOException {
+        //Given
+        BodyPart inlinedHTMLPart = BodyPartBuilder.create()
+            .setBody(HTML_CONTENT, "html", StandardCharsets.UTF_8)
+            .build();
+        HeaderImpl inlinedHeader = new HeaderImpl();
+        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
+        inlinedHeader.addField(Fields.contentType("text/html; charset=utf-8"));
+        inlinedHeader.addField(CONTENT_ID_FIELD);
+        inlinedHTMLPart.setHeader(inlinedHeader);
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+            .addBodyPart(inlinedHTMLPart)
+            .build();
+        Message message = Message.Builder.of()
+            .setBody(multipartAlternative)
+            .build();
+
+        //When
+        MessageContent actual = testee.extract(message);
+
+        //Then
+        assertThat(actual.getHtmlBody()).isEmpty();
+    }
+
+
+    @Test
+    public void extractShouldRetrieveTextBodyWithOneInlinedTextAttachmentWithoutCid() throws IOException {
+        //Given
+        BodyPart inlinedTextPart = BodyPartBuilder.create()
+            .setBody(TEXT_CONTENT, "text", StandardCharsets.UTF_8)
+            .build();
+        HeaderImpl inlinedHeader = new HeaderImpl();
+        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
+        inlinedHeader.addField(Fields.contentType("text/plain; charset=utf-8"));
+        inlinedTextPart.setHeader(inlinedHeader);
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+            .addBodyPart(inlinedTextPart)
+            .build();
+        Message message = Message.Builder.of()
+            .setBody(multipartAlternative)
+            .build();
+
+        //When
+        MessageContent actual = testee.extract(message);
+
+        //Then
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+    }
+
+    @Test
+    public void extractShouldNotRetrieveTextBodyWithOneInlinedTextAttachmentWithCid() throws IOException {
+        //Given
+        BodyPart inlinedTextPart = BodyPartBuilder.create()
+            .setBody(TEXT_CONTENT, "text", StandardCharsets.UTF_8)
+            .build();
+        HeaderImpl inlinedHeader = new HeaderImpl();
+        inlinedHeader.addField(Fields.contentDisposition(MimeMessage.INLINE));
+        inlinedHeader.addField(Fields.contentType("text/plain; charset=utf-8"));
+        inlinedHeader.addField(CONTENT_ID_FIELD);
+        inlinedTextPart.setHeader(inlinedHeader);
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+            .addBodyPart(inlinedTextPart)
+            .build();
+        Message message = Message.Builder.of()
+            .setBody(multipartAlternative)
+            .build();
+
+        //When
+        MessageContent actual = testee.extract(message);
+
+        //Then
+        assertThat(actual.getTextBody()).isEmpty();
+    }
+
+    @Test
+    public void extractShouldRetrieveTextAndHtmlBodyWhenOneInlinedTextAttachmentAndMainContentInMultipart() throws IOException {
+        BodyPart multipartAlternative = BodyPartBuilder.create()
+                .setBody(MultipartBuilder.create("alternative")
+                        .addBodyPart(textPart)
+                        .addBodyPart(htmlPart)
+                        .build())
+                .build();
+
+        Multipart multipartMixed = MultipartBuilder.create("mixed")
+                .addBodyPart(multipartAlternative)
+                .addBodyPart(inlineText)
+                .build();
+
+        Message message = Message.Builder.of()
+                .setBody(multipartMixed)
+                .build();
+
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void extractShouldRetrieveTextBodyAndHtmlBodyWhenTextBodyInMainMultipartAndHtmlBodyInInnerMultipart() throws IOException {
+        BodyPart multipartRelated = BodyPartBuilder.create()
+                .setBody(MultipartBuilder.create("related")
+                        .addBodyPart(htmlPart)
+                        .addBodyPart(inlineImage)
+                        .build())
+                .build();
+
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+                .addBodyPart(textPart)
+                .addBodyPart(multipartRelated)
+                .build();
+
+        Message message = Message.Builder.of()
+                .setBody(multipartAlternative)
+                .build();
+
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnEmptyWhenAllEmpty() {
+        MessageContent messageContent1 = MessageContent.empty();
+        MessageContent messageContent2 = MessageContent.empty();
+        MessageContent expected = MessageContent.empty();
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnFirstWhenSecondEmpty() {
+        MessageContent messageContent1 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = MessageContent.empty();
+        MessageContent expected = messageContent1;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnSecondWhenFirstEmpty() {
+        MessageContent messageContent1 = MessageContent.empty();
+        MessageContent messageContent2 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent expected = messageContent2;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnMixWhenFirstTextOnlyAndSecondHtmlOnly() {
+        MessageContent messageContent1 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
+        MessageContent messageContent2 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
+        MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnMixWhenFirstHtmlOnlyAndSecondTextOnly() {
+        MessageContent messageContent1 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
+        MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnFirstWhenTwiceAreComplete() {
+        MessageContent messageContent1 = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = new MessageContent(Optional.of(TEXT_CONTENT2), Optional.of(HTML_CONTENT2));
+        MessageContent expected = messageContent1;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void extractShouldRespectCharsetWhenOtherThanUTF8() throws IOException {
+        String text = "éééé\r\nèèèè\r\nàààà";
+        Message message = Message.Builder.of()
+                .setBody(text, Charset.forName("windows-1252"))
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(text);
+    }
+
+    @Test
+    public void extractShouldRespectCharsetWhenUTF8() throws IOException {
+        String text = "éééé\r\nèèèè\r\nàààà";
+        Message message = Message.Builder.of()
+                .setBody(text, StandardCharsets.UTF_8)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(text);
+    }
+
+    @Test
+    public void extractShouldUseUSASCIIWhenNoCharset() throws IOException {
+        String text = "éééé\r\nèèèè\r\nàààà";
+        Message message = Message.Builder.of()
+                .setBody(text, null)
+                .build();
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains("????\r\n????\r\n????");
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java b/server/container/util/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
new file mode 100644
index 0000000..8c9c98b
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/streams/ImmutableCollectorsTest.java
@@ -0,0 +1,123 @@
+/****************************************************************
+ * 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.util.streams;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.data.MapEntry.entry;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class ImmutableCollectorsTest {
+
+    @Test
+    public void immutableListCollectorShouldReturnEmptyImmutableListWhenEmptyStream() {
+        String[] data = {};
+        List<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableList());
+        assertThat(actual).isInstanceOf(ImmutableList.class);
+        assertThat(actual).isEmpty();
+    }
+    
+    @Test
+    public void immutableListCollectorShouldReturnImmutableListWhenOneElementStream() {
+        String[] data = {"a"};
+        List<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableList());
+        assertThat(actual).isInstanceOf(ImmutableList.class);
+        assertThat(actual).containsExactly("a");
+    }
+    
+    @Test
+    public void immutableListCollectorShouldReturnImmutableListWhen3ElementsStream() {
+        String[] data = {"a", "b", "c"};
+        List<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableList());
+        assertThat(actual).isInstanceOf(ImmutableList.class);
+        assertThat(actual).containsExactly("a", "b", "c");
+    }
+
+    @Test
+    public void immutableSetCollectorShouldReturnEmptyImmutableSetWhenEmptyStream() {
+        String[] data = {};
+        Set<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableSet());
+        assertThat(actual).isInstanceOf(ImmutableSet.class);
+        assertThat(actual).isEmpty();
+    }
+
+    @Test
+    public void immutableSetCollectorShouldReturnImmutableSetWhenOneElementStream() {
+        String[] data = {"a"};
+        Set<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableSet());
+        assertThat(actual).isInstanceOf(ImmutableSet.class);
+        assertThat(actual).containsExactly("a");
+    }
+
+    @Test
+    public void immutableSetCollectorShouldReturnImmutableSetWhen3ElementsStream() {
+        String[] data = {"a", "b", "c"};
+        Set<String> actual = Arrays.stream(data)
+            .collect(Guavate.toImmutableSet());
+        assertThat(actual).isInstanceOf(ImmutableSet.class);
+        assertThat(actual).containsExactly("a", "b", "c");
+    }
+
+
+    @Test
+    public void immutableMapCollectorShouldReturnEmptyImmutableMapWhenEmptyStream() {
+        String[] data = {};
+        Map<String, Integer> actual = Arrays.stream(data)
+                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
+        assertThat(actual).isInstanceOf(ImmutableMap.class);
+        assertThat(actual).isEmpty();
+    }
+    
+    @Test
+    public void immutableMapCollectorShouldReturnAppliedImmutableMapWhenOneElementStream() {
+        String[] data = {"a"};
+        Map<String, Integer> actual = Arrays.stream(data)
+                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
+        assertThat(actual).isInstanceOf(ImmutableMap.class);
+        assertThat(actual).containsExactly(entry("A", 1));
+    }
+    
+    @Test
+    public void immutableMapCollectorShouldReturnAppliedImmutableMapWhen3ElementsStream() {
+        String[] data = {"a", "bb", "ccc"};
+        Map<String, Integer> actual = Arrays.stream(data)
+                .collect(Guavate.toImmutableMap(x -> x.toUpperCase(Locale.US), String::length));
+        assertThat(actual).isInstanceOf(ImmutableMap.class);
+        assertThat(actual).containsExactly(entry("A", 1), entry("BB", 2), entry("CCC", 3));
+    }
+    
+}
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/streams/IteratorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/streams/IteratorsTest.java b/server/container/util/src/test/java/org/apache/james/util/streams/IteratorsTest.java
new file mode 100644
index 0000000..4c63f1a
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/streams/IteratorsTest.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * 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.util.streams;
+
+import static java.util.stream.Collectors.toList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.UnmodifiableIterator;
+
+public class IteratorsTest {
+
+    @Test
+    public void toStreamShouldReturnEmptyStreamWhenEmptyIterator() {
+        //Given
+        UnmodifiableIterator<String> emptyIterator = ImmutableList.<String>of().iterator();
+
+        //When
+        Stream<String> actual = Iterators.toStream(emptyIterator);
+
+        //Then
+        assertThat(actual.count()).isEqualTo(0);
+    }
+
+    @Test
+    public void toStreamShouldReturnSameContent() {
+        //Given
+        UnmodifiableIterator<String> iterator = ImmutableList.of("a", "b", "c").iterator();
+
+        //When
+        Stream<String> actual = Iterators.toStream(iterator);
+
+        //Then
+        assertThat(actual.collect(toList())).containsExactly("a", "b", "c");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java b/server/container/util/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
new file mode 100644
index 0000000..52f1c3a
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/streams/JamesCollectorsTest.java
@@ -0,0 +1,121 @@
+/****************************************************************
+ * 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.util.streams;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+public class JamesCollectorsTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void chunkerShouldAcceptEmptyStrem() {
+        Stream<Integer> emptyStream = Stream.of();
+
+        assertThat(emptyStream.collect(JamesCollectors.chunker(10))
+            .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void chunkerShouldThrowOnZeroChunkSize() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        JamesCollectors.chunker(0);
+    }
+
+    @Test
+    public void chunkerShouldThrowOnNegativeChunkSize() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        JamesCollectors.chunker(-1);
+    }
+
+    @Test
+    public void chunkerShouldChunkMonoValueStreams() {
+        Stream<Integer> monoValueStream = Stream.of(1);
+
+        List<List<Integer>> values = monoValueStream.collect(JamesCollectors.chunker(10))
+            .map(ImmutableList::copyOf)
+            .collect(Guavate.toImmutableList());
+        assertThat(values)
+            .isEqualTo(ImmutableList.of(ImmutableList.of(1)));
+    }
+
+    @Test
+    public void chunkerShouldChunkStreamsSmallerThanChunkSize() {
+        Stream<Integer> stream = Stream.of(1, 2);
+
+        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
+            .map(ImmutableList::copyOf)
+            .collect(Guavate.toImmutableList());
+        assertThat(values)
+            .isEqualTo(ImmutableList.of(ImmutableList.of(1, 2)));
+    }
+
+    @Test
+    public void chunkerShouldChunkStreamsAsBigAsChunkSize() {
+        Stream<Integer> stream = Stream.of(1, 2, 3);
+
+        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
+            .map(ImmutableList::copyOf)
+            .collect(Guavate.toImmutableList());
+        assertThat(values)
+            .isEqualTo(ImmutableList.of(ImmutableList.of(1, 2, 3)));
+    }
+
+    @Test
+    public void chunkerShouldChunkStreamsBiggerThanChunkSize() {
+        Stream<Integer> stream = Stream.of(1, 2, 3, 4);
+
+        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
+            .map(ImmutableList::copyOf)
+            .collect(Guavate.toImmutableList());
+        assertThat(values)
+            .isEqualTo(ImmutableList.of(
+                ImmutableList.of(1, 2, 3),
+                ImmutableList.of(4)));
+    }
+
+    @Test
+    public void chunkerShouldChunkInSeveralBuckets() {
+        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7);
+
+        List<List<Integer>> values = stream.collect(JamesCollectors.chunker(3))
+            .map(ImmutableList::copyOf)
+            .collect(Guavate.toImmutableList());
+        assertThat(values)
+            .isEqualTo(ImmutableList.of(
+                ImmutableList.of(1, 2, 3),
+                ImmutableList.of(4, 5, 6),
+                ImmutableList.of(7)));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/streams/LimitTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/streams/LimitTest.java b/server/container/util/src/test/java/org/apache/james/util/streams/LimitTest.java
new file mode 100644
index 0000000..fcd92d8
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/streams/LimitTest.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * 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.util.streams;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class LimitTest {
+
+    private final List<Integer> aList = ImmutableList.of(1, 2, 3, 4, 5, 6);
+
+    @Rule
+    public final ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void unlimitedShouldCreateLimitWithNoLimit() {
+        Limit testee = Limit.unlimited();
+        assertThat(testee.getLimit()).isEqualTo(Optional.empty());
+    }
+
+    @Test
+    public void beanShouldRespectBeanContract() {
+        EqualsVerifier.forClass(Limit.class)
+            .verify();
+    }
+
+    @Test
+    public void unlimitedShouldCreateLimitThatDoesNotAffectStream() {
+
+        Limit testee = Limit.unlimited();
+        assertThat(
+            testee
+                .applyOnStream(aList.stream())
+                .collect(Guavate.toImmutableList())
+        ).isEqualTo(aList);
+    }
+
+    @Test
+    public void limitShouldCreateLimitWithNoLimit() {
+        int expected = 3;
+
+        Limit testee = Limit.limit(expected);
+        assertThat(testee.getLimit())
+            .isEqualTo(Optional.of(expected));
+    }
+
+    @Test
+    public void limitShouldCreateLimitThatCorrectlyTruncateStream() {
+        Limit testee = Limit.limit(3);
+
+        assertThat(testee
+            .applyOnStream(aList.stream())
+            .collect(Guavate.toImmutableList())
+        ).isEqualTo(ImmutableList.of(1, 2, 3));
+    }
+
+    @Test
+    public void limitShouldThrowAnErrorWhenCalledWithZero() {
+        expectedException.expect(IllegalArgumentException.class);
+        Limit.limit(0);
+    }
+
+
+    @Test
+    public void limitShouldThrowAnErrorWhenCalledWithNegativeValue() {
+        expectedException.expect(IllegalArgumentException.class);
+        Limit.limit(-1);
+    }
+
+    @Test
+    public void ofShouldTakePositiveValueAsLimit() {
+        assertThat(Limit.from(3))
+            .isEqualTo(Limit.limit(3));
+    }
+
+    @Test
+    public void ofShouldTakeNegativeValueAsUnlimited() {
+        assertThat(Limit.from(-1))
+            .isEqualTo(Limit.unlimited());
+    }
+
+    @Test
+    public void ofShouldTakeZeroValueAsUnlimited() {
+        assertThat(Limit.from(0))
+            .isEqualTo(Limit.unlimited());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/streams/OffsetTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/streams/OffsetTest.java b/server/container/util/src/test/java/org/apache/james/util/streams/OffsetTest.java
new file mode 100644
index 0000000..45d8e6d
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/streams/OffsetTest.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * 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.util.streams;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class OffsetTest {
+
+    public static final int VALUE = 18;
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(Offset.class)
+            .verify();
+    }
+
+    @Test
+    public void fromZeroShouldBeEquivalentToNone() {
+        assertThat(Offset.from(0))
+            .isEqualTo(Offset.none());
+    }
+
+    @Test
+    public void getOffsetShouldReturnContainedValue() {
+        assertThat(Offset.from(VALUE).getOffset())
+            .isEqualTo(VALUE);
+    }
+
+    @Test
+    public void fromOptionalShouldBeEquivalentToFromValueWhenPresent() {
+        assertThat(Offset.from(Optional.of(VALUE)))
+            .isEqualTo(Offset.from(VALUE));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/data/data-jmap/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/pom.xml b/server/data/data-jmap/pom.xml
index a859470..7c7f049 100644
--- a/server/data/data-jmap/pom.xml
+++ b/server/data/data-jmap/pom.xml
@@ -39,7 +39,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/data/data-ldap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-ldap-integration-testing/pom.xml b/server/data/data-ldap-integration-testing/pom.xml
index 4b5919c..1e4ba59 100644
--- a/server/data/data-ldap-integration-testing/pom.xml
+++ b/server/data/data-ldap-integration-testing/pom.xml
@@ -40,7 +40,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/mailet/integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/pom.xml b/server/mailet/integration-testing/pom.xml
index 3a53ffc..5ddb093 100644
--- a/server/mailet/integration-testing/pom.xml
+++ b/server/mailet/integration-testing/pom.xml
@@ -94,7 +94,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/mailet/mailetcontainer-camel/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/mailetcontainer-camel/pom.xml b/server/mailet/mailetcontainer-camel/pom.xml
index cfe4148..044afc2 100644
--- a/server/mailet/mailetcontainer-camel/pom.xml
+++ b/server/mailet/mailetcontainer-camel/pom.xml
@@ -99,7 +99,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
index 0380b9c..576c1eb 100644
--- a/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
+++ b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/pom.xml
@@ -125,12 +125,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <!-- Force Memory JMAP integration tests to be played before Cassandra ones -->
             <groupId>${james.groupId}</groupId>
             <artifactId>memory-jmap-integration-testing</artifactId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
index b109376..26c1261 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/pom.xml
@@ -99,12 +99,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-webadmin-core</artifactId>
             <type>test-jar</type>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
index 180cab6..9b7c8ad 100644
--- a/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
+++ b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/pom.xml
@@ -96,12 +96,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>javax-mail-extension</artifactId>
             <type>test-jar</type>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/jmap/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/pom.xml b/server/protocols/jmap/pom.xml
index f8eebce..83514ff 100644
--- a/server/protocols/jmap/pom.xml
+++ b/server/protocols/jmap/pom.xml
@@ -135,11 +135,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/protocols-imap4/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-imap4/pom.xml b/server/protocols/protocols-imap4/pom.xml
index ec64dd9..da3d952 100644
--- a/server/protocols/protocols-imap4/pom.xml
+++ b/server/protocols/protocols-imap4/pom.xml
@@ -43,7 +43,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/protocols-managesieve/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-managesieve/pom.xml b/server/protocols/protocols-managesieve/pom.xml
index 1b510ed..98e0227 100644
--- a/server/protocols/protocols-managesieve/pom.xml
+++ b/server/protocols/protocols-managesieve/pom.xml
@@ -43,7 +43,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.protocols.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/webadmin/webadmin-core/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/pom.xml b/server/protocols/webadmin/webadmin-core/pom.xml
index 2633e55..8df8461 100644
--- a/server/protocols/webadmin/webadmin-core/pom.xml
+++ b/server/protocols/webadmin/webadmin-core/pom.xml
@@ -43,7 +43,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/webadmin/webadmin-data/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-data/pom.xml b/server/protocols/webadmin/webadmin-data/pom.xml
index f767608..7cca591 100644
--- a/server/protocols/webadmin/webadmin-data/pom.xml
+++ b/server/protocols/webadmin/webadmin-data/pom.xml
@@ -56,7 +56,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index 5c91f4a..8499f92 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -102,7 +102,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/protocols/webadmin/webadmin-mailrepository/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/pom.xml b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
index abc9d2f..4d120ec 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
@@ -62,7 +62,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/queue/queue-rabbitmq/pom.xml
----------------------------------------------------------------------
diff --git a/server/queue/queue-rabbitmq/pom.xml b/server/queue/queue-rabbitmq/pom.xml
index 7244a13..8d61023 100644
--- a/server/queue/queue-rabbitmq/pom.xml
+++ b/server/queue/queue-rabbitmq/pom.xml
@@ -35,7 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/task/pom.xml
----------------------------------------------------------------------
diff --git a/server/task/pom.xml b/server/task/pom.xml
index 10a0704..80534c6 100644
--- a/server/task/pom.xml
+++ b/server/task/pom.xml
@@ -33,7 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>junit</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/testing/pom.xml
----------------------------------------------------------------------
diff --git a/server/testing/pom.xml b/server/testing/pom.xml
index c689d7b..f50652f 100644
--- a/server/testing/pom.xml
+++ b/server/testing/pom.xml
@@ -41,7 +41,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
         </dependency>
         <dependency>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[04/14] james-project git commit: JAMES-2502 fix Eclipse Photon build for mailets, utils and imap

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java
new file mode 100644
index 0000000..6791a1f
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java
@@ -0,0 +1,464 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.Mail;
+import org.apache.mailet.PerRecipientHeaders;
+import org.apache.mailet.PerRecipientHeaders.Header;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public class FakeMail implements Mail, Serializable {
+
+    private static final String DEFAULT_REMOTE_HOST = "111.222.333.444";
+    public static final String DEFAULT_REMOTE_ADDRESS = "127.0.0.1";
+
+    public static FakeMail fromMessage(MimeMessageBuilder message) throws MessagingException {
+        return FakeMail.builder()
+            .mimeMessage(message)
+            .build();
+    }
+
+    public static FakeMail fromMime(String text, String javaEncodingCharset, String javamailDefaultEncodingCharset) throws MessagingException, UnsupportedEncodingException {
+        Properties javamailProperties = new Properties();
+        javamailProperties.setProperty("mail.mime.charset", javamailDefaultEncodingCharset);
+        return FakeMail.builder()
+                .mimeMessage(MimeMessageUtil.mimeMessageFromBytes((text.getBytes(javaEncodingCharset))))
+                .build();
+    }
+
+    public static FakeMail fromMail(Mail mail) throws MessagingException {
+        return new FakeMail(mail.getMessage(),
+            Lists.newArrayList(mail.getRecipients()),
+            mail.getName(),
+            mail.getSender(),
+            mail.getState(),
+            mail.getErrorMessage(),
+            mail.getLastUpdated(),
+            attributes(mail),
+            mail.getMessageSize(),
+            mail.getRemoteAddr(),
+            mail.getRemoteHost(),
+            mail.getPerRecipientSpecificHeaders());
+    }
+
+    public static FakeMail from(MimeMessage message) throws MessagingException {
+        return builder()
+                .mimeMessage(message)
+                .build();
+    }
+
+    public static FakeMail from(MimeMessageBuilder message) throws MessagingException {
+        return from(message.build());
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+
+        private Optional<String> fileName;
+        private Optional<MimeMessage> mimeMessage;
+        private List<MailAddress> recipients;
+        private Optional<String> name;
+        private Optional<MailAddress> sender;
+        private Optional<String> state;
+        private Optional<String> errorMessage;
+        private Optional<Date> lastUpdated;
+        private Map<String, Serializable> attributes;
+        private Optional<Long> size;
+        private Optional<String> remoteAddr;
+        private Optional<String> remoteHost;
+        private PerRecipientHeaders perRecipientHeaders;
+
+        private Builder() {
+            fileName = Optional.empty();
+            mimeMessage = Optional.empty();
+            recipients = Lists.newArrayList();
+            name = Optional.empty();
+            sender = Optional.empty();
+            state = Optional.empty();
+            errorMessage = Optional.empty();
+            lastUpdated = Optional.empty();
+            attributes = Maps.newHashMap();
+            size = Optional.empty();
+            remoteAddr = Optional.empty();
+            remoteHost = Optional.empty();
+            perRecipientHeaders = new PerRecipientHeaders();
+        }
+
+        public Builder size(long size) {
+            this.size = Optional.of(size);
+            return this;
+        }
+
+        public Builder fileName(String fileName) {
+            this.fileName = Optional.of(fileName);
+            return this;
+        }
+
+        public Builder mimeMessage(MimeMessage mimeMessage) {
+            this.mimeMessage = Optional.of(mimeMessage);
+            return this;
+        }
+
+        public Builder mimeMessage(MimeMessageBuilder mimeMessage) throws MessagingException {
+            this.mimeMessage = Optional.of(mimeMessage.build());
+            return this;
+        }
+
+        public Builder recipients() {
+            return this;
+        }
+
+        public Builder recipients(List<MailAddress> recipients) {
+            this.recipients.addAll(recipients);
+            return this;
+        }
+
+        public Builder recipients(MailAddress... recipients) {
+            return recipients(ImmutableList.copyOf(recipients));
+        }
+
+        public Builder recipients(String... recipients) {
+            return recipients(Arrays.stream(recipients)
+                .map(Throwing.function(MailAddress::new))
+                .collect(Guavate.toImmutableList()));
+        }
+
+        public Builder recipient(MailAddress recipient) {
+            return recipients(recipient);
+        }
+
+        public Builder recipient(String recipient) throws AddressException {
+            return recipients(recipient);
+        }
+
+        public Builder name(String name) {
+            this.name = Optional.of(name);
+            return this;
+        }
+
+        public Builder sender(MailAddress sender) {
+            this.sender = Optional.of(sender);
+            return this;
+        }
+
+        public Builder sender(String sender) throws AddressException {
+            return sender(new MailAddress(sender));
+        }
+
+        public Builder state(String state) {
+            this.state = Optional.of(state);
+            return this;
+        }
+
+        public Builder errorMessage(String errorMessage) {
+            this.errorMessage = Optional.of(errorMessage);
+            return this;
+        }
+
+        public Builder lastUpdated(Date lastUpdated) {
+            this.lastUpdated = Optional.of(lastUpdated);
+            return this;
+        }
+
+        public Builder attribute(String name, Serializable object) {
+            this.attributes.put(name, object);
+            return this;
+        }
+
+        public Builder attributes(Map<String, Serializable> attributes) {
+            this.attributes.putAll(attributes);
+            return this;
+        }
+
+        public Builder remoteAddr(String remoteAddr) {
+            this.remoteAddr = Optional.of(remoteAddr);
+            return this;
+        }
+
+        public Builder remoteHost(String remoteHost) {
+            this.remoteHost = Optional.of(remoteHost);
+            return this;
+        }
+
+        public Builder addHeaderForRecipient(Header header, MailAddress recipient) {
+            this.perRecipientHeaders.addHeaderForRecipient(header, recipient);
+            return this;
+        }
+
+        public FakeMail build() throws MessagingException {
+            return new FakeMail(getMimeMessage(), recipients, name.orElse(null), sender.orElse(null), state.orElse(null), errorMessage.orElse(null), lastUpdated.orElse(null),
+                attributes, size.orElse(0L), remoteAddr.orElse(DEFAULT_REMOTE_ADDRESS), remoteHost.orElse(DEFAULT_REMOTE_HOST), perRecipientHeaders);
+        }
+
+        private MimeMessage getMimeMessage() throws MessagingException {
+            Preconditions.checkState(!(fileName.isPresent() && mimeMessage.isPresent()), "You can not specify a MimeMessage object when you alredy set Content from a file");
+            if (fileName.isPresent()) {
+                return MimeMessageUtil.mimeMessageFromStream(ClassLoader.getSystemResourceAsStream(fileName.get()));
+            }
+            return mimeMessage.orElse(null);
+        }
+    }
+
+    public static FakeMail defaultFakeMail() throws MessagingException {
+        return FakeMail.builder().build();
+    }
+
+    private static Map<String, Serializable> attributes(Mail mail) {
+        ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.builder();
+        for (String attributeName: ImmutableList.copyOf(mail.getAttributeNames())) {
+            builder.put(attributeName, mail.getAttribute(attributeName));
+        }
+        return builder.build();
+    }
+
+    private transient MimeMessage msg;
+    private Collection<MailAddress> recipients;
+    private String name;
+    private MailAddress sender;
+    private String state;
+    private String errorMessage;
+    private Date lastUpdated;
+    private Map<String, Serializable> attributes;
+    private long size;
+    private String remoteAddr;
+    private String remoteHost;
+    private PerRecipientHeaders perRecipientHeaders;
+    
+    public FakeMail(MimeMessage msg, List<MailAddress> recipients, String name, MailAddress sender, String state, String errorMessage, Date lastUpdated,
+            Map<String, Serializable> attributes, long size, String remoteAddr, String remoteHost, PerRecipientHeaders perRecipientHeaders) {
+        this.msg = msg;
+        this.recipients = recipients;
+        this.name = name;
+        this.sender = sender;
+        this.state = state;
+        this.errorMessage = errorMessage;
+        this.lastUpdated = lastUpdated;
+        this.attributes = attributes;
+        this.size = size;
+        this.remoteAddr = remoteAddr;
+        this.perRecipientHeaders = perRecipientHeaders;
+        this.remoteHost = remoteHost;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(String newName) {
+        this.name = newName;
+    }
+
+    @Override
+    public MimeMessage getMessage() throws MessagingException {
+        return msg;
+    }
+
+    @Override
+    public Collection<MailAddress> getRecipients() {
+        return recipients;
+    }
+
+    @Override
+    public void setRecipients(Collection<MailAddress> recipients) {
+        this.recipients = recipients;
+    }
+
+    @Override
+    public MailAddress getSender() {
+        return sender;
+    }
+
+    @Override
+    public String getState() {
+        return state;
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return remoteHost;
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        return remoteAddr;
+    }
+
+    @Override
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    @Override
+    public void setErrorMessage(String msg) {
+        this.errorMessage = msg;
+    }
+
+    @Override
+    public void setMessage(MimeMessage message) {
+        this.msg = message;
+        try {
+            if (message != null && message.getSender() != null) {
+                this.sender = new MailAddress((InternetAddress) message.getSender());
+            }
+        } catch (MessagingException e) {
+            throw new RuntimeException("Exception caught", e);
+        }
+    }
+
+    @Override
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    @Override
+    public Serializable getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    @Override
+    public Iterator<String> getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+    @Override
+    public boolean hasAttributes() {
+        return !attributes.isEmpty();
+    }
+
+    @Override
+    public Serializable removeAttribute(String name) {
+        return attributes.remove(name);
+
+    }
+
+    @Override
+    public void removeAllAttributes() {
+        attributes.clear();
+    }
+
+    @Override
+    public Serializable setAttribute(String name, Serializable object) {
+        return attributes.put(name, object);
+    }
+
+    @Override
+    public long getMessageSize() throws MessagingException {
+        return size;
+    }
+
+    @Override
+    public Date getLastUpdated() {
+        return lastUpdated;
+    }
+
+    @Override
+    public void setLastUpdated(Date lastUpdated) {
+        this.lastUpdated = lastUpdated;
+    }
+
+    public void setMessageSize(long size) {
+        this.size = size;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof FakeMail) {
+            FakeMail that = (FakeMail) o;
+
+            return Objects.equal(this.size, that.size)
+                && Objects.equal(this.recipients, that.recipients)
+                && Objects.equal(this.name, that.name)
+                && Objects.equal(this.sender, that.sender)
+                && Objects.equal(this.state, that.state)
+                && Objects.equal(this.errorMessage, that.errorMessage)
+                && Objects.equal(this.lastUpdated, that.lastUpdated)
+                && Objects.equal(this.attributes, that.attributes)
+                && Objects.equal(this.remoteHost, that.remoteHost)
+                && Objects.equal(this.perRecipientHeaders, that.perRecipientHeaders)
+                && Objects.equal(this.remoteAddr, that.remoteAddr);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hashCode(name, sender, recipients, state, errorMessage, lastUpdated, attributes, size, remoteAddr, remoteHost, perRecipientHeaders);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("msg", msg)
+            .add("recipients", recipients)
+            .add("name", name)
+            .add("sender", sender)
+            .add("state", state)
+            .add("errorMessage", errorMessage)
+            .add("lastUpdated", lastUpdated)
+            .add("attributes", attributes)
+            .add("size", size)
+            .add("remoteAddr", remoteAddr)
+            .toString();
+    }
+
+    @Override
+    public PerRecipientHeaders getPerRecipientSpecificHeaders() {
+        return perRecipientHeaders;
+    }
+
+    @Override
+    public void addSpecificHeaderForRecipient(Header header, MailAddress recipient) {
+        perRecipientHeaders.addHeaderForRecipient(header, recipient);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
new file mode 100644
index 0000000..eff41c9
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
@@ -0,0 +1,608 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.core.Domain;
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.builder.MimeMessageWrapper;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.LookupException;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
+import org.slf4j.Logger;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.functions.ThrowingFunction;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+@SuppressWarnings("deprecation")
+public class FakeMailContext implements MailetContext {
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static SentMail.Builder sentMailBuilder() {
+        return new SentMail.Builder();
+    }
+
+    public static SentMail.Builder fromMail(Mail mail) throws MessagingException {
+        return sentMailBuilder()
+            .sender(mail.getSender())
+            .recipients(mail.getRecipients())
+            .message(mail.getMessage())
+            .state(mail.getState())
+            .attributes(buildAttributesMap(mail))
+            .fromMailet();
+    }
+
+    private static ImmutableMap<String, Serializable> buildAttributesMap(Mail mail) {
+        Map<String, Serializable> result = new HashMap<>();
+        List<String> attributesNames = Lists.newArrayList(mail.getAttributeNames());
+        for (String attributeName: attributesNames) {
+            result.put(attributeName, mail.getAttribute(attributeName));
+        }
+        return ImmutableMap.copyOf(result);
+    }
+
+    public static FakeMailContext defaultContext() {
+        return builder().build();
+    }
+
+    public static class Builder {
+
+        private Logger logger;
+        private Optional<MailAddress> postmaster;
+
+        private Builder() {
+            postmaster = Optional.empty();
+        }
+
+        public Builder logger(Logger logger) {
+            this.logger = logger;
+            return this;
+        }
+
+        public Builder postmaster(MailAddress postmaster) {
+            this.postmaster = Optional.of(postmaster);
+            return this;
+        }
+
+        public FakeMailContext build() {
+            return new FakeMailContext(Optional.ofNullable(logger), postmaster.orElse(null));
+        }
+    }
+
+    public static class SentMail {
+
+        private static MimeMessage tryCopyMimeMessage(MimeMessage msg) throws MessagingException {
+            ThrowingFunction<MimeMessage, MimeMessage> throwingFunction = MimeMessageWrapper::wrap;
+
+            return Optional.ofNullable(msg)
+                .map(Throwing.function(throwingFunction).sneakyThrow())
+                .orElse(null);
+        }
+
+        public static class Builder {
+            private MailAddress sender;
+            private Optional<Collection<MailAddress>> recipients = Optional.empty();
+            private MimeMessage msg;
+            private Map<String, Serializable> attributes = new HashMap<>();
+            private Optional<String> state = Optional.empty();
+            private Optional<Boolean> fromMailet = Optional.empty();
+            private Optional<Delay> delay = Optional.empty();
+
+            public Builder sender(MailAddress sender) {
+                this.sender = sender;
+                return this;
+            }
+
+            public Builder sender(String sender) throws AddressException {
+                return sender(new MailAddress(sender));
+            }
+
+            public Builder recipients(Collection<MailAddress> recipients) {
+                this.recipients = Optional.of(recipients);
+                return this;
+            }
+
+            public Builder fromMailet() {
+                this.fromMailet = Optional.of(true);
+                return this;
+            }
+
+            public Builder recipients(MailAddress... recipients) {
+                this.recipients = Optional.<Collection<MailAddress>>of(ImmutableList.copyOf(recipients));
+                return this;
+            }
+
+            public Builder recipient(MailAddress recipient) {
+                Preconditions.checkNotNull(recipient);
+                return recipients(ImmutableList.of(recipient));
+            }
+
+            public Builder recipient(String recipient) throws AddressException {
+                Preconditions.checkNotNull(recipient);
+                return recipients(new MailAddress(recipient));
+            }
+
+            public Builder message(MimeMessage mimeMessage) {
+                this.msg = mimeMessage;
+                return this;
+            }
+
+            public Builder attributes(Map<String, Serializable> attributes) {
+                this.attributes.putAll(attributes);
+                return this;
+            }
+
+            public Builder attribute(String key, Serializable value) {
+                this.attributes.put(key, value);
+                return this;
+            }
+
+            public Builder state(String state) {
+                this.state = Optional.of(state);
+                return this;
+            }
+
+            public Builder delay(Delay delay) {
+                this.delay = Optional.of(delay);
+                return this;
+            }
+
+            public SentMail build() throws MessagingException {
+                if (fromMailet.orElse(false)) {
+                    this.attribute(Mail.SENT_BY_MAILET, "true");
+                }
+                return new SentMail(sender, recipients.orElse(ImmutableList.<MailAddress>of()), msg,
+                    ImmutableMap.copyOf(attributes), state.orElse(Mail.DEFAULT), delay);
+            }
+        }
+
+        private final MailAddress sender;
+        private final Collection<MailAddress> recipients;
+        private final MimeMessage msg;
+        private final Optional<String> subject;
+        private final Map<String, Serializable> attributes;
+        private final String state;
+        private final Optional<Delay> delay;
+
+        private SentMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, Map<String, Serializable> attributes, String state, Optional<Delay> delay) throws MessagingException {
+            this.sender = sender;
+            this.recipients = ImmutableList.copyOf(recipients);
+            this.msg = tryCopyMimeMessage(msg);
+            this.subject = getSubject(msg);
+            this.attributes = ImmutableMap.copyOf(attributes);
+            this.state = state;
+            this.delay = delay;
+        }
+
+        private Optional<String> getSubject(MimeMessage msg) {
+            try {
+                return Optional.ofNullable(msg.getSubject());
+            } catch (Exception e) {
+                return Optional.empty();
+            }
+        }
+
+        public MailAddress getSender() {
+            return sender;
+        }
+
+        public Collection<MailAddress> getRecipients() {
+            return recipients;
+        }
+
+        public MimeMessage getMsg() {
+            return msg;
+        }
+
+        public String getState() {
+            return state;
+        }
+
+        public Optional<String> getSubject() {
+            return subject;
+        }
+
+
+        public Optional<Delay> getDelay() {
+            return delay;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof SentMail)) {
+                return false;
+            }
+
+            SentMail sentMail = (SentMail) o;
+
+            return Objects.equals(this.sender, sentMail.sender)
+                && Objects.equals(this.recipients, sentMail.recipients)
+                && Objects.equals(this.attributes, sentMail.attributes)
+                && Objects.equals(this.state, sentMail.state);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(sender, recipients, attributes, state);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("recipients", recipients)
+                .add("sender", sender)
+                .add("attributeNames", attributes)
+                .add("state", state)
+                .toString();
+        }
+    }
+
+    public static class Delay {
+        private final long duration;
+        private final TimeUnit timeUnit;
+
+        public Delay(long duration, TimeUnit timeUnit) {
+            this.duration = duration;
+            this.timeUnit = timeUnit;
+        }
+
+        public long getDuration() {
+            return duration;
+        }
+
+        public TimeUnit getTimeUnit() {
+            return timeUnit;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof Delay) {
+                Delay delay = (Delay) o;
+
+                return Objects.equals(this.duration, delay.duration)
+                    && Objects.equals(this.timeUnit, delay.timeUnit);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(duration, timeUnit);
+        }
+    }
+
+    public static class BouncedMail {
+        private final SentMail sentMail;
+        private final String message;
+        private final Optional<MailAddress> bouncer;
+
+        public BouncedMail(SentMail sentMail, String message, Optional<MailAddress> bouncer) {
+            this.sentMail = sentMail;
+            this.message = message;
+            this.bouncer = bouncer;
+        }
+
+        public BouncedMail(SentMail.Builder sentMail, String message, Optional<MailAddress> bouncer) throws MessagingException {
+            this(sentMail.build(), message, bouncer);
+        }
+
+        public SentMail getSentMail() {
+            return sentMail;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public Optional<MailAddress> getBouncer() {
+            return bouncer;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o instanceof BouncedMail) {
+                BouncedMail that = (BouncedMail) o;
+                return Objects.equals(this.sentMail, that.sentMail)
+                    && Objects.equals(this.message, that.message)
+                    && Objects.equals(this.bouncer, that.bouncer);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(sentMail, message, bouncer);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("sentMail", sentMail)
+                .add("message", message)
+                .add("bouncer", bouncer)
+                .toString();
+        }
+    }
+
+    private final HashMap<String, Object> attributes;
+    private final Collection<SentMail> sentMails;
+    private final Collection<BouncedMail> bouncedMails;
+    private final Optional<Logger> logger;
+    private final MailAddress postmaster;
+
+    private FakeMailContext(Optional<Logger> logger, MailAddress postmaster) {
+        attributes = new HashMap<>();
+        sentMails = new ConcurrentLinkedQueue<>();
+        bouncedMails = new ConcurrentLinkedQueue<>();
+        this.logger = logger;
+        this.postmaster = postmaster;
+    }
+
+    @Override
+    public void bounce(Mail mail, String message) throws MessagingException {
+        bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.empty()));
+    }
+
+    @Override
+    public void bounce(Mail mail, String message, MailAddress bouncer) throws MessagingException {
+        bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.ofNullable(bouncer)));
+    }
+
+    /**
+     * @deprecated use the generic dnsLookup method
+     */
+    @Override
+    public Collection<String> getMailServers(Domain host) {
+        return null;  // trivial implementation
+    }
+
+    @Override
+    public MailAddress getPostmaster() {
+        return postmaster;
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    @Override
+    public Iterator<String> getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+    @Override
+    public int getMajorVersion() {
+        return 0;  // trivial implementation
+    }
+
+    @Override
+    public int getMinorVersion() {
+        return 0;  // trivial implementation
+    }
+
+    @Override
+    public String getServerInfo() {
+        return "Mock Server";
+    }
+
+    @Override
+    public boolean isLocalServer(Domain domain) {
+        return domain.equals(Domain.LOCALHOST);
+    }
+
+    /**
+     * @deprecated use {@link #isLocalEmail(MailAddress)} instead 
+     */
+    @Override
+    public boolean isLocalUser(String userAccount) {
+        return false;  // trivial implementation
+    }
+
+    @Override
+    public boolean isLocalEmail(MailAddress mailAddress) {
+        return false;  // trivial implementation
+    }
+
+    /**
+     * @deprecated use {@link #log(LogLevel level, String message)}
+     */
+    @Override
+    public void log(String message) {
+        System.out.println(message);
+    }
+
+    /**
+     * @deprecated use {@link #log(LogLevel level, String message, Throwable t)}
+     */
+    @Override
+    public void log(String message, Throwable t) {
+        System.out.println(message);
+        t.printStackTrace(System.out);
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        // trivial implementation
+    }
+
+    @Override
+    public void sendMail(MimeMessage mimemessage) throws MessagingException {
+        sentMails.add(sentMailBuilder()
+            .message(mimemessage)
+            .fromMailet()
+            .build());
+    }
+
+    @Override
+    public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg) throws MessagingException {
+        sentMails.add(sentMailBuilder()
+            .recipients(recipients)
+            .sender(sender)
+            .message(msg)
+            .fromMailet()
+            .build());
+    }
+
+    @Override
+    public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, String state) throws MessagingException {
+        sentMails.add(sentMailBuilder()
+            .recipients(recipients)
+            .message(msg)
+            .state(state)
+            .sender(sender)
+            .fromMailet()
+            .build());
+    }
+
+    @Override
+    public void sendMail(Mail mail) throws MessagingException {
+        sendMail(mail, Mail.DEFAULT);
+    }
+
+    @Override
+    public void sendMail(Mail mail, long delay, TimeUnit unit) throws MessagingException {
+        sendMail(mail, Mail.DEFAULT, delay, unit);
+    }
+
+    @Override
+    public void sendMail(Mail mail, String state) throws MessagingException {
+        mail.setState(state);
+        sentMails.add(fromMail(mail).build());
+    }
+
+    @Override
+    public void sendMail(Mail mail, String state, long delay, TimeUnit unit) throws MessagingException {
+        mail.setState(state);
+        sentMails.add(
+            fromMail(mail)
+                .delay(new Delay(delay, unit))
+                .build());
+    }
+
+    public void setAttribute(String name, Serializable object) {
+        attributes.put(name,object);
+    }
+
+    public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg) throws MessagingException {
+        // trivial implementation
+    }
+
+    /**
+     * @deprecated use the generic dnsLookup method
+     */
+    @Override
+    public Iterator<HostAddress> getSMTPHostAddresses(Domain domainName) {
+        return null;  // trivial implementation
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        throw new UnsupportedOperationException("MOCKed method");
+    }
+
+    @Override
+    public void log(LogLevel level, String message) {
+        if (logger.isPresent()) {
+            switch (level) {
+            case INFO:
+                logger.get().info(message);
+                break;
+            case WARN:
+                logger.get().warn(message);
+                break;
+            case ERROR:
+                logger.get().error(message);
+                break;
+            default:
+                logger.get().debug(message);
+            }
+        } else {
+            System.out.println("[" + level + "]" + message);
+        }
+    }
+
+    @Override
+    public void log(LogLevel level, String message, Throwable t) {
+        if (logger.isPresent()) {
+            switch (level) {
+            case INFO:
+                logger.get().info(message, t);
+                break;
+            case WARN:
+                logger.get().warn(message, t);
+                break;
+            case ERROR:
+                logger.get().error(message, t);
+                break;
+            default:
+                logger.get().debug(message, t);
+            }
+        } else {
+            System.out.println("[" + level + "]" + message);
+            t.printStackTrace(System.out);
+        }
+    }
+
+    @Override
+    public List<String> dnsLookup(String name, RecordType type) throws LookupException {
+        return null;   // trivial implementation
+    }
+
+    public List<SentMail> getSentMails() {
+        return ImmutableList.copyOf(sentMails);
+    }
+
+    public void resetSentMails() {
+        sentMails.clear();
+    }
+
+    public List<BouncedMail> getBouncedMails() {
+        return ImmutableList.copyOf(bouncedMails);
+    }
+
+    @Override
+    public Logger getLogger() {
+        return logger.orElse(null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailetConfig.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailetConfig.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailetConfig.java
new file mode 100644
index 0000000..73289d7
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailetConfig.java
@@ -0,0 +1,106 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.Properties;
+
+import org.apache.mailet.MailetConfig;
+import org.apache.mailet.MailetContext;
+
+/**
+ * MailetConfig over Properties
+ */
+public class FakeMailetConfig implements MailetConfig {
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+
+        private static final String DEFAULT_MAILET_NAME = "A Mailet";
+        private Optional<String> mailetName;
+        private Optional<MailetContext> mailetContext;
+        private Properties properties;
+
+        private Builder() {
+            mailetName = Optional.empty();
+            mailetContext = Optional.empty();
+            properties = new Properties();
+        }
+
+        public Builder mailetName(String mailetName) {
+            this.mailetName = Optional.ofNullable(mailetName);
+            return this;
+        }
+
+        public Builder mailetContext(MailetContext mailetContext) {
+            this.mailetContext = Optional.ofNullable(mailetContext);
+            return this;
+        }
+
+        public Builder mailetContext(FakeMailContext.Builder mailetContext) {
+            return mailetContext(mailetContext.build());
+        }
+
+        public Builder setProperty(String key, String value) {
+            this.properties.setProperty(key, value);
+            return this;
+        }
+
+        public FakeMailetConfig build() {
+            return new FakeMailetConfig(mailetName.orElse(DEFAULT_MAILET_NAME),
+                    mailetContext.orElse(FakeMailContext.defaultContext()),
+                    properties);
+        }
+    }
+
+    private final String mailetName;
+    private final MailetContext mailetContext;
+    private final Properties properties;
+
+    private FakeMailetConfig(String mailetName, MailetContext mailetContext, Properties properties) {
+        this.mailetName = mailetName;
+        this.mailetContext = mailetContext;
+        this.properties = properties;
+    }
+
+    @Override
+    public String getInitParameter(String name) {
+        return properties.getProperty(name);
+    }
+
+    @Override
+    public Iterator<String> getInitParameterNames() {
+        return properties.stringPropertyNames().iterator();
+    }
+
+    @Override
+    public MailetContext getMailetContext() {
+        return mailetContext;
+    }
+
+    @Override
+    public String getMailetName() {
+        return mailetName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMatcherConfig.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMatcherConfig.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMatcherConfig.java
new file mode 100644
index 0000000..1917c3d
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMatcherConfig.java
@@ -0,0 +1,95 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import java.util.Optional;
+
+import org.apache.mailet.MailetContext;
+import org.apache.mailet.MatcherConfig;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * MatcherConfig
+ */
+public class FakeMatcherConfig implements MatcherConfig {
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+
+        private String matcherName;
+        private Optional<MailetContext> mailetContext;
+        private Optional<String> condition;
+
+        private Builder() {
+            condition = Optional.empty();
+            mailetContext = Optional.empty();
+        }
+
+        public Builder matcherName(String matcherName) {
+            this.matcherName = matcherName;
+            return this;
+        }
+
+        public Builder mailetContext(MailetContext mailetContext) {
+            Preconditions.checkNotNull(mailetContext);
+            this.mailetContext = Optional.of(mailetContext);
+            return this;
+        }
+
+        public Builder condition(String condition) {
+            this.condition = Optional.ofNullable(condition);
+            return this;
+        }
+
+        public FakeMatcherConfig build() {
+            Preconditions.checkNotNull(matcherName, "'matcherName' is mandatory");
+            return new FakeMatcherConfig(matcherName, mailetContext.orElse(FakeMailContext.defaultContext()), condition);
+        }
+    }
+
+    private final String matcherName;
+    private final MailetContext mailetContext;
+    private final Optional<String> condition;
+
+    private FakeMatcherConfig(String matcherName, MailetContext mailetContext, Optional<String> condition) {
+        this.matcherName = matcherName;
+        this.mailetContext = mailetContext;
+        this.condition = condition;
+    }
+
+    @Override
+    public String getMatcherName() {
+        return matcherName;
+    }
+
+    @Override
+    public MailetContext getMailetContext() {
+        return mailetContext;
+    }
+
+    @Override
+    public String getCondition() {
+        return condition.orElse(null);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/test/MailUtil.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/MailUtil.java b/mailet/test/src/main/java/org/apache/mailet/base/test/MailUtil.java
new file mode 100644
index 0000000..ecbee4f
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/MailUtil.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.mailet.Mail;
+
+/**
+ * some utilities for James unit testing
+ */
+public class MailUtil {
+
+    public static final String SENDER = "test@james.apache.org";
+    public static final String RECIPIENT = "test2@james.apache.org";
+    private static int m_counter = 0;
+
+    public static String newId() {
+        m_counter++;
+        return "MockMailUtil-ID-" + m_counter;
+    }
+
+    public static FakeMail createMockMail2Recipients() throws MessagingException {
+        return FakeMail.builder()
+                .name(newId())
+                .recipients(new MailAddress("test@james.apache.org"), new MailAddress("test2@james.apache.org"))
+                .build();
+    }
+
+    public static FakeMail createMockMail2Recipients(MimeMessage message) throws MessagingException {
+        return FakeMail.builder()
+                .name(newId())
+                .mimeMessage(message)
+                .recipients(new MailAddress("test@james.apache.org"), new MailAddress("test2@james.apache.org"))
+                .build();
+    }
+
+    public static MimeMessage createMimeMessage() throws MessagingException {
+        return createMimeMessage(null, null);
+    }
+    
+    public static MimeMessage createMimeMessageWithSubject(String subject) throws MessagingException {
+        return createMimeMessage(null, null, subject);
+    }
+
+    public static MimeMessage createMimeMessage(String headerName, String headerValue) throws MessagingException {
+        return createMimeMessage(headerName, headerValue, "testmail");
+    }
+    
+    private static MimeMessage createMimeMessage(String headerName, String headerValue, String subject) throws MessagingException {
+        MimeMessageBuilder mimeMessageBuilder = MimeMessageBuilder.mimeMessageBuilder()
+            .addToRecipient(RECIPIENT)
+            .addFrom(SENDER)
+            .setSubject(subject);
+        if (headerName != null) {
+            mimeMessageBuilder.addHeader(headerName, headerValue);
+        }
+        return mimeMessageBuilder.build();
+    }
+    
+    public static String toString(Mail mail, String charset) throws IOException, MessagingException {
+        ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
+        mail.getMessage().writeTo(
+                rawMessage,
+                new String[] { "Bcc", "Content-Length", "Message-ID" });
+        return rawMessage.toString(charset);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/test/java/org/apache/mailet/base/test/FakeMailTest.java b/mailet/test/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
new file mode 100644
index 0000000..fc0c03c
--- /dev/null
+++ b/mailet/test/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * 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.mailet.base.test;
+
+import static org.mockito.Mockito.mock;
+
+import javax.mail.internet.MimeMessage;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+public class FakeMailTest {
+
+    @Test
+    public void beanShouldRespectBeanContract() {
+        EqualsVerifier.forClass(FakeMail.class)
+            .suppress(Warning.NONFINAL_FIELDS)
+            .withPrefabValues(MimeMessage.class, mock(MimeMessage.class), mock(MimeMessage.class))
+            .verify();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mpt/impl/imap-mailbox/core/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/imap-mailbox/core/pom.xml b/mpt/impl/imap-mailbox/core/pom.xml
index 83d17d4..b8075ff 100644
--- a/mpt/impl/imap-mailbox/core/pom.xml
+++ b/mpt/impl/imap-mailbox/core/pom.xml
@@ -85,11 +85,6 @@
             <artifactId>protocols-imap</artifactId>
         </dependency>
         <dependency>
-            <groupId>${james.protocols.groupId}</groupId>
-            <artifactId>protocols-imap</artifactId>
-            <type>test-jar</type>
-        </dependency>
-        <dependency>
             <groupId>org.jmock</groupId>
             <artifactId>jmock</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0164ebe..669d927 100644
--- a/pom.xml
+++ b/pom.xml
@@ -982,6 +982,11 @@
             </dependency>
             <dependency>
                 <groupId>${james.groupId}</groupId>
+                <artifactId>apache-mailet-test</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+             <dependency>
+                <groupId>${james.groupId}</groupId>
                 <artifactId>apache-mime4j-core</artifactId>
                 <version>${apache-mime4j.version}</version>
                 <exclusions>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/main/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
new file mode 100644
index 0000000..4fedc02
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
@@ -0,0 +1,105 @@
+/****************************************************************
+ * 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.imap.decode;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.protocols.imap.DecodingException;
+import org.apache.james.protocols.imap.utils.EolInputStream;
+import org.apache.james.protocols.imap.utils.FixedLengthInputStream;
+
+/**
+ * {@link ImapRequestLineReader} which use normal IO Streaming
+ */
+public class ImapRequestStreamLineReader extends ImapRequestLineReader {
+    private final InputStream input;
+
+    private final OutputStream output;
+
+    public ImapRequestStreamLineReader(InputStream input, OutputStream output) {
+        this.input = input;
+        this.output = output;
+    }
+
+    /**
+     * Reads the next character in the current line. This method will continue
+     * to return the same character until the {@link #consume()} method is
+     * called.
+     * 
+     * @return The next character TODO: character encoding is variable and
+     *         cannot be determine at the token level; this char is not accurate
+     *         reported; should be an octet
+     * @throws DecodingException
+     *             If the end-of-stream is reached.
+     */
+    @Override
+    public char nextChar() throws DecodingException {
+        if (!nextSeen) {
+            int next = -1;
+
+            try {
+                next = input.read();
+            } catch (IOException e) {
+                throw new DecodingException(HumanReadableText.SOCKET_IO_FAILURE, "Error reading from stream.", e);
+            }
+            if (next == -1) {
+                throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unexpected end of stream.");
+            }
+
+            nextSeen = true;
+            nextChar = (char) next;
+        }
+        return nextChar;
+    }
+
+    @Override
+    public InputStream read(int size, boolean extraCRLF) throws DecodingException {
+
+        // Unset the next char.
+        nextSeen = false;
+        nextChar = 0;
+        FixedLengthInputStream in = new FixedLengthInputStream(input, size);
+        if (extraCRLF) {
+            return new EolInputStream(this, in);
+        } else {
+            return in;
+        }
+    }
+
+    /**
+     * Sends a server command continuation request '+' back to the client,
+     * requesting more data to be sent.
+     */
+    @Override
+    protected void commandContinuationRequest() throws DecodingException {
+        try {
+            output.write('+');
+            output.write('\r');
+            output.write('\n');
+            output.flush();
+        } catch (IOException e) {
+            throw new DecodingException(HumanReadableText.SOCKET_IO_FAILURE, "Unexpected exception in sending command continuation request.", e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/main/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
new file mode 100644
index 0000000..f720a6a
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
@@ -0,0 +1,129 @@
+/****************************************************************
+ * 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.imap.decode.main;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.james.imap.api.ImapSessionState;
+import org.apache.james.imap.api.process.ImapProcessor;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.decode.ImapDecoder;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.apache.james.imap.decode.ImapRequestStreamLineReader;
+import org.apache.james.imap.encode.ImapEncoder;
+import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
+import org.apache.james.imap.main.AbstractImapRequestHandler;
+import org.apache.james.imap.message.request.SystemMessage;
+import org.apache.james.protocols.imap.DecodingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ */
+public final class ImapRequestStreamHandler extends AbstractImapRequestHandler {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ImapRequestStreamHandler.class);
+
+    public ImapRequestStreamHandler(ImapDecoder decoder, ImapProcessor processor, ImapEncoder encoder) {
+        super(decoder, processor, encoder);
+    }
+
+    /**
+     * This method parses IMAP commands read off the wire in handleConnection.
+     * Actual processing of the command (possibly including additional back and
+     * forth communication with the client) is delegated to one of a number of
+     * command specific handler methods. The primary purpose of this method is
+     * to parse the raw command string to determine exactly which handler should
+     * be called. It returns true if expecting additional commands, false
+     * otherwise.
+     * 
+     * @return whether additional commands are expected.
+     */
+    public boolean handleRequest(InputStream input, OutputStream output, ImapSession session) {
+        final boolean result;
+        if (isSelectedMailboxDeleted(session)) {
+            writeSignoff(output, session);
+            result = false;
+        } else {
+            ImapRequestLineReader request = new ImapRequestStreamLineReader(input, output);
+
+            try {
+                request.nextChar();
+            } catch (DecodingException e) {
+                LOGGER.debug("Unexpected end of line. Cannot handle request: ", e);
+                abandon(output, session);
+                return false;
+            }
+
+            ImapResponseComposerImpl response = new ImapResponseComposerImpl(new OutputStreamImapResponseWriter(output));
+
+            if (doProcessRequest(request, response, session)) {
+
+                try {
+                    // Consume the rest of the line, throwing away any extras.
+                    // This allows us to clean up after a protocol error.
+                    request.consumeLine();
+                } catch (DecodingException e) {
+                    // Cannot clean up. No recovery is therefore possible.
+                    // Abandon connection.
+                    LOGGER.info("Fault during clean up: {}", e.getMessage());
+                    LOGGER.debug("Abandoning after fault in clean up", e);
+                    abandon(output, session);
+                    return false;
+                }
+
+                result = !(ImapSessionState.LOGOUT == session.getState());
+            } else {
+                LOGGER.debug("Connection was abandoned after request processing failed.");
+                result = false;
+                abandon(output, session);
+            }
+        }
+        return result;
+    }
+
+    private void writeSignoff(OutputStream output, ImapSession session) {
+        try {
+            output.write(MAILBOX_DELETED_SIGNOFF);
+        } catch (IOException e) {
+            LOGGER.warn("Failed to write signoff");
+            LOGGER.debug("Failed to write signoff:", e);
+        }
+    }
+
+    private void abandon(OutputStream out, ImapSession session) {
+        if (session != null) {
+            try {
+                session.logout();
+            } catch (Throwable t) {
+                LOGGER.warn("Session logout failed. Resources may not be correctly recycled.");
+            }
+        }
+        try {
+            out.write(ABANDON_SIGNOFF);
+        } catch (Throwable t) {
+            LOGGER.debug("Failed to write ABANDON_SIGNOFF", t);
+        }
+        processor.process(SystemMessage.FORCE_LOGOUT, new SilentResponder(), session);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/main/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
new file mode 100644
index 0000000..4ceaad6
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * 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.imap.decode.main;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.james.imap.encode.ImapResponseWriter;
+import org.apache.james.imap.message.response.Literal;
+
+/**
+ * Class providing methods to send response messages from the server to the
+ * client.
+ */
+public class OutputStreamImapResponseWriter implements ImapResponseWriter {
+
+    private final OutputStream output;
+
+    public OutputStreamImapResponseWriter(OutputStream output) {
+        this.output = output;
+    }
+
+    public void flush() throws IOException {
+        output.flush();
+    }
+
+
+
+    @Override
+    public void write(Literal literal) throws IOException {
+        InputStream in = null;
+        try {
+            in = literal.getInputStream();
+
+            byte[] buffer = new byte[1024];
+            for (int len; (len = in.read(buffer)) != -1;) {
+                output.write(buffer, 0, len);
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+
+    }
+
+    @Override
+    public void write(byte[] buffer) throws IOException {
+        output.write(buffer);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java b/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java
new file mode 100644
index 0000000..bd7d053
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java
@@ -0,0 +1,145 @@
+/****************************************************************
+ * 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.imap.encode;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.james.imap.api.ImapSessionState;
+import org.apache.james.imap.api.process.ImapLineHandler;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.api.process.SelectedMailbox;
+
+public class FakeImapSession implements ImapSession {
+
+    private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
+
+    private SelectedMailbox selectedMailbox = null;
+
+    private final Map<String, Object> attributesByKey;
+
+    public FakeImapSession() {
+        this.attributesByKey = new ConcurrentHashMap<>();
+    }
+
+    @Override
+    public void logout() {
+        closeMailbox();
+        state = ImapSessionState.LOGOUT;
+    }
+
+    @Override
+    public void authenticated() {
+        this.state = ImapSessionState.AUTHENTICATED;
+    }
+
+    @Override
+    public void deselect() {
+        this.state = ImapSessionState.AUTHENTICATED;
+        closeMailbox();
+    }
+
+    @Override
+    public void selected(SelectedMailbox mailbox) {
+        this.state = ImapSessionState.SELECTED;
+        closeMailbox();
+        this.selectedMailbox = mailbox;
+    }
+
+    @Override
+    public SelectedMailbox getSelected() {
+        return this.selectedMailbox;
+    }
+
+    @Override
+    public ImapSessionState getState() {
+        return this.state;
+    }
+
+    public void closeMailbox() {
+        if (selectedMailbox != null) {
+            selectedMailbox.deselect();
+            selectedMailbox = null;
+        }
+    }
+
+    @Override
+    public Object getAttribute(String key) {
+        return attributesByKey.get(key);
+    }
+
+    @Override
+    public void setAttribute(String key, Object value) {
+        if (value == null) {
+            attributesByKey.remove(key);
+        } else {
+            attributesByKey.put(key, value);
+        }
+    }
+    
+    @Override
+    public boolean startTLS() {
+        return false;
+    }
+
+    @Override
+    public boolean supportStartTLS() {
+        return false;
+    }
+
+    @Override
+    public boolean isCompressionSupported() {
+        return false;
+    }
+
+    @Override
+    public boolean startCompression() {
+        return false;
+    }
+
+    @Override
+    public void pushLineHandler(ImapLineHandler lineHandler) {
+    }
+
+    @Override
+    public void popLineHandler() {
+        
+    }
+
+    @Override
+    public boolean isPlainAuthDisallowed() {
+        return false;
+    }
+
+    @Override
+    public boolean isTLSActive() {
+        return false;
+    }
+
+    @Override
+    public boolean supportMultipleNamespaces() {
+        return false;
+    }
+
+    @Override
+    public boolean isCompressionActive() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/test/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java b/protocols/imap/src/test/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
deleted file mode 100644
index 4fedc02..0000000
--- a/protocols/imap/src/test/java/org/apache/james/imap/decode/ImapRequestStreamLineReader.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************
- * 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.imap.decode;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.protocols.imap.DecodingException;
-import org.apache.james.protocols.imap.utils.EolInputStream;
-import org.apache.james.protocols.imap.utils.FixedLengthInputStream;
-
-/**
- * {@link ImapRequestLineReader} which use normal IO Streaming
- */
-public class ImapRequestStreamLineReader extends ImapRequestLineReader {
-    private final InputStream input;
-
-    private final OutputStream output;
-
-    public ImapRequestStreamLineReader(InputStream input, OutputStream output) {
-        this.input = input;
-        this.output = output;
-    }
-
-    /**
-     * Reads the next character in the current line. This method will continue
-     * to return the same character until the {@link #consume()} method is
-     * called.
-     * 
-     * @return The next character TODO: character encoding is variable and
-     *         cannot be determine at the token level; this char is not accurate
-     *         reported; should be an octet
-     * @throws DecodingException
-     *             If the end-of-stream is reached.
-     */
-    @Override
-    public char nextChar() throws DecodingException {
-        if (!nextSeen) {
-            int next = -1;
-
-            try {
-                next = input.read();
-            } catch (IOException e) {
-                throw new DecodingException(HumanReadableText.SOCKET_IO_FAILURE, "Error reading from stream.", e);
-            }
-            if (next == -1) {
-                throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unexpected end of stream.");
-            }
-
-            nextSeen = true;
-            nextChar = (char) next;
-        }
-        return nextChar;
-    }
-
-    @Override
-    public InputStream read(int size, boolean extraCRLF) throws DecodingException {
-
-        // Unset the next char.
-        nextSeen = false;
-        nextChar = 0;
-        FixedLengthInputStream in = new FixedLengthInputStream(input, size);
-        if (extraCRLF) {
-            return new EolInputStream(this, in);
-        } else {
-            return in;
-        }
-    }
-
-    /**
-     * Sends a server command continuation request '+' back to the client,
-     * requesting more data to be sent.
-     */
-    @Override
-    protected void commandContinuationRequest() throws DecodingException {
-        try {
-            output.write('+');
-            output.write('\r');
-            output.write('\n');
-            output.flush();
-        } catch (IOException e) {
-            throw new DecodingException(HumanReadableText.SOCKET_IO_FAILURE, "Unexpected exception in sending command continuation request.", e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/test/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java b/protocols/imap/src/test/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
deleted file mode 100644
index f720a6a..0000000
--- a/protocols/imap/src/test/java/org/apache/james/imap/decode/main/ImapRequestStreamHandler.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************
- * 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.imap.decode.main;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.james.imap.api.ImapSessionState;
-import org.apache.james.imap.api.process.ImapProcessor;
-import org.apache.james.imap.api.process.ImapSession;
-import org.apache.james.imap.decode.ImapDecoder;
-import org.apache.james.imap.decode.ImapRequestLineReader;
-import org.apache.james.imap.decode.ImapRequestStreamLineReader;
-import org.apache.james.imap.encode.ImapEncoder;
-import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
-import org.apache.james.imap.main.AbstractImapRequestHandler;
-import org.apache.james.imap.message.request.SystemMessage;
-import org.apache.james.protocols.imap.DecodingException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 
- */
-public final class ImapRequestStreamHandler extends AbstractImapRequestHandler {
-    private static final Logger LOGGER = LoggerFactory.getLogger(ImapRequestStreamHandler.class);
-
-    public ImapRequestStreamHandler(ImapDecoder decoder, ImapProcessor processor, ImapEncoder encoder) {
-        super(decoder, processor, encoder);
-    }
-
-    /**
-     * This method parses IMAP commands read off the wire in handleConnection.
-     * Actual processing of the command (possibly including additional back and
-     * forth communication with the client) is delegated to one of a number of
-     * command specific handler methods. The primary purpose of this method is
-     * to parse the raw command string to determine exactly which handler should
-     * be called. It returns true if expecting additional commands, false
-     * otherwise.
-     * 
-     * @return whether additional commands are expected.
-     */
-    public boolean handleRequest(InputStream input, OutputStream output, ImapSession session) {
-        final boolean result;
-        if (isSelectedMailboxDeleted(session)) {
-            writeSignoff(output, session);
-            result = false;
-        } else {
-            ImapRequestLineReader request = new ImapRequestStreamLineReader(input, output);
-
-            try {
-                request.nextChar();
-            } catch (DecodingException e) {
-                LOGGER.debug("Unexpected end of line. Cannot handle request: ", e);
-                abandon(output, session);
-                return false;
-            }
-
-            ImapResponseComposerImpl response = new ImapResponseComposerImpl(new OutputStreamImapResponseWriter(output));
-
-            if (doProcessRequest(request, response, session)) {
-
-                try {
-                    // Consume the rest of the line, throwing away any extras.
-                    // This allows us to clean up after a protocol error.
-                    request.consumeLine();
-                } catch (DecodingException e) {
-                    // Cannot clean up. No recovery is therefore possible.
-                    // Abandon connection.
-                    LOGGER.info("Fault during clean up: {}", e.getMessage());
-                    LOGGER.debug("Abandoning after fault in clean up", e);
-                    abandon(output, session);
-                    return false;
-                }
-
-                result = !(ImapSessionState.LOGOUT == session.getState());
-            } else {
-                LOGGER.debug("Connection was abandoned after request processing failed.");
-                result = false;
-                abandon(output, session);
-            }
-        }
-        return result;
-    }
-
-    private void writeSignoff(OutputStream output, ImapSession session) {
-        try {
-            output.write(MAILBOX_DELETED_SIGNOFF);
-        } catch (IOException e) {
-            LOGGER.warn("Failed to write signoff");
-            LOGGER.debug("Failed to write signoff:", e);
-        }
-    }
-
-    private void abandon(OutputStream out, ImapSession session) {
-        if (session != null) {
-            try {
-                session.logout();
-            } catch (Throwable t) {
-                LOGGER.warn("Session logout failed. Resources may not be correctly recycled.");
-            }
-        }
-        try {
-            out.write(ABANDON_SIGNOFF);
-        } catch (Throwable t) {
-            LOGGER.debug("Failed to write ABANDON_SIGNOFF", t);
-        }
-        processor.process(SystemMessage.FORCE_LOGOUT, new SilentResponder(), session);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/protocols/imap/src/test/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java b/protocols/imap/src/test/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
deleted file mode 100644
index 4ceaad6..0000000
--- a/protocols/imap/src/test/java/org/apache/james/imap/decode/main/OutputStreamImapResponseWriter.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************
- * 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.imap.decode.main;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.james.imap.encode.ImapResponseWriter;
-import org.apache.james.imap.message.response.Literal;
-
-/**
- * Class providing methods to send response messages from the server to the
- * client.
- */
-public class OutputStreamImapResponseWriter implements ImapResponseWriter {
-
-    private final OutputStream output;
-
-    public OutputStreamImapResponseWriter(OutputStream output) {
-        this.output = output;
-    }
-
-    public void flush() throws IOException {
-        output.flush();
-    }
-
-
-
-    @Override
-    public void write(Literal literal) throws IOException {
-        InputStream in = null;
-        try {
-            in = literal.getInputStream();
-
-            byte[] buffer = new byte[1024];
-            for (int len; (len = in.read(buffer)) != -1;) {
-                output.write(buffer, 0, len);
-            }
-        } finally {
-            if (in != null) {
-                in.close();
-            }
-        }
-
-    }
-
-    @Override
-    public void write(byte[] buffer) throws IOException {
-        output.write(buffer);
-    }
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[12/14] james-project git commit: MAILBOX-342 Use a singleton and surefire::reuseforks to launch a single cassandra container

Posted by ma...@apache.org.
MAILBOX-342 Use a singleton and surefire::reuseforks to launch a single cassandra container


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/524e43ab
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/524e43ab
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/524e43ab

Branch: refs/heads/master
Commit: 524e43abc9704513a5d0f1fc21081d1a317442a6
Parents: 8cd1e2c
Author: benwa <bt...@linagora.com>
Authored: Tue Jul 24 15:36:53 2018 +0700
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:32:01 2018 +0200

----------------------------------------------------------------------
 backends-common/cassandra/pom.xml               |  12 +++
 .../ContainerLifecycleConfiguration.java        |   4 +
 .../backends/cassandra/DockerCassandra.java     | 107 +++++++++++++++++++
 .../backends/cassandra/DockerCassandraRule.java |  83 ++------------
 .../cassandra/DockerCassandraSingleton.java     |  36 +++++++
 mailbox/cassandra/pom.xml                       |  12 +++
 .../CassandraMessageIdToImapUidDAOTest.java     |   2 +
 mpt/impl/imap-mailbox/cassandra/pom.xml         |  12 +++
 mpt/impl/smtp/cassandra/pom.xml                 |  12 +++
 server/container/guice/cassandra-guice/pom.xml  |   7 ++
 server/data/data-cassandra/pom.xml              |   7 ++
 server/data/data-jmap-cassandra/pom.xml         |   7 ++
 .../mailrepository-cassandra/pom.xml            |   7 ++
 .../protocols/webadmin-integration-test/pom.xml |  12 +++
 14 files changed, 246 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/backends-common/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/pom.xml b/backends-common/cassandra/pom.xml
index 9be80f7..7516b2b 100644
--- a/backends-common/cassandra/pom.xml
+++ b/backends-common/cassandra/pom.xml
@@ -134,4 +134,16 @@
         </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/ContainerLifecycleConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/ContainerLifecycleConfiguration.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/ContainerLifecycleConfiguration.java
index 0768f51..d9592f9 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/ContainerLifecycleConfiguration.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/ContainerLifecycleConfiguration.java
@@ -28,6 +28,10 @@ import org.testcontainers.shaded.com.google.common.base.Preconditions;
 
 public class ContainerLifecycleConfiguration {
 
+    public static Builder builder() {
+        return new Builder();
+    }
+
     public static Builder withDefaultIterationsBetweenRestart() {
         return new Builder();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
new file mode 100644
index 0000000..bb0feec
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
@@ -0,0 +1,107 @@
+/****************************************************************
+ * 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.backends.cassandra;
+
+import org.apache.james.util.Host;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.OutputFrame;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
+
+import com.github.dockerjava.api.DockerClient;
+
+public class DockerCassandra {
+
+    private static final Logger logger = LoggerFactory.getLogger(DockerCassandra.class);
+
+    private static final int CASSANDRA_PORT = 9042;
+    private static final String CASSANDRA_CONFIG_DIR = "$CASSANDRA_CONFIG";
+    private static final String CASSANDRA_YAML = CASSANDRA_CONFIG_DIR + "/cassandra.yaml";
+    private static final String CASSANDRA_ENV = CASSANDRA_CONFIG_DIR + "/cassandra-env.sh";
+    private static final String JVM_OPTIONS = CASSANDRA_CONFIG_DIR + "/jvm.options";
+
+    private final GenericContainer<?> cassandraContainer;
+    private final DockerClient client;
+
+    @SuppressWarnings("resource")
+    public DockerCassandra() {
+        client = DockerClientFactory.instance().client();
+        boolean deleteOnExit = false;
+        int cassandraMemory = 1000;
+        long cassandraContainerMemory = Float.valueOf(cassandraMemory * 1.2f * 1024 * 1024L).longValue();
+        cassandraContainer = new GenericContainer<>(
+            new ImageFromDockerfile("cassandra_2_2_12", deleteOnExit)
+                .withDockerfileFromBuilder(builder ->
+                    builder
+                        .from("cassandra:2.2.12")
+                        .env("ENV CASSANDRA_CONFIG", "/etc/cassandra")
+                        .run("echo \"-Xms" + cassandraMemory + "M\" >> " + JVM_OPTIONS)
+                        .run("echo \"-Xmx" + cassandraMemory + "M\" >> " + JVM_OPTIONS)
+                        .build()))
+            .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig().withTmpFs(ImmutableMap.of("/var/lib/cassandra", "rw,noexec,nosuid,size=200m")))
+            .withCreateContainerCmdModifier(cmd -> cmd.withMemory(cassandraContainerMemory))
+            .withExposedPorts(CASSANDRA_PORT)
+            .withLogConsumer(DockerCassandra::displayDockerLog);
+        cassandraContainer
+            .waitingFor(new CassandraWaitStrategy(cassandraContainer));
+    }
+
+    private static void displayDockerLog(OutputFrame outputFrame) {
+        logger.info(outputFrame.getUtf8String());
+    }
+
+    public void start() {
+        cassandraContainer.start();
+    }
+
+    public void stop() {
+        cassandraContainer.stop();
+    }
+
+    public Host getHost() {
+        return Host.from(
+            getIp(),
+            getBindingPort());
+    }
+    
+    public String getIp() {
+        return cassandraContainer.getContainerIpAddress();
+    }
+
+    public int getBindingPort() {
+        return cassandraContainer.getMappedPort(CASSANDRA_PORT);
+    }
+
+    public GenericContainer<?> getRawContainer() {
+        return cassandraContainer;
+    }
+
+    public void pause() {
+        client.pauseContainerCmd(cassandraContainer.getContainerId());
+    }
+
+    public void unpause() {
+        client.unpauseContainerCmd(cassandraContainer.getContainerId());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraRule.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraRule.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraRule.java
index 6f634dd..b3eb35e 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraRule.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraRule.java
@@ -23,111 +23,46 @@ import org.apache.james.util.Host;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testcontainers.DockerClientFactory;
 import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.containers.output.OutputFrame;
-import org.testcontainers.images.builder.ImageFromDockerfile;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
-
-import com.github.dockerjava.api.DockerClient;
 
 
 public class DockerCassandraRule implements TestRule {
 
-    private static final Logger logger = LoggerFactory.getLogger(DockerCassandraRule.class);
-
-    private static final int CASSANDRA_PORT = 9042;
-    private static final String CASSANDRA_CONFIG_DIR = "$CASSANDRA_CONFIG";
-    private static final String CASSANDRA_YAML = CASSANDRA_CONFIG_DIR + "/cassandra.yaml";
-    private static final String CASSANDRA_ENV = CASSANDRA_CONFIG_DIR + "/cassandra-env.sh";
-    private static final String JVM_OPTIONS = CASSANDRA_CONFIG_DIR + "/jvm.options";
-
-    private final GenericContainer<?> cassandraContainer;
-    private final DockerClient client;
-
-    @SuppressWarnings("resource")
-    public DockerCassandraRule() {
-        client = DockerClientFactory.instance().client();
-        boolean deleteOnExit = false;
-        cassandraContainer = new GenericContainer<>(
-            new ImageFromDockerfile("cassandra_2_2_12", deleteOnExit)
-                .withDockerfileFromBuilder(builder ->
-                    builder
-                        .from("cassandra:2.2.12")
-                        .env("ENV CASSANDRA_CONFIG", "/etc/cassandra")
-                        //avoiding token range computation helps starting faster
-                        .run("echo \"JVM_OPTS=\\\"\\$JVM_OPTS -Dcassandra.initial_token=0\\\"\" >> " + CASSANDRA_ENV)
-                        .run("sed -i -e \"s/num_tokens/\\#num_tokens/\" " + CASSANDRA_YAML)
-                        //don't wait for other nodes communication to happen
-                        .run("echo \"JVM_OPTS=\\\"\\$JVM_OPTS -Dcassandra.skip_wait_for_gossip_to_settle=0\\\"\" >> " + CASSANDRA_ENV)
-                        //make sure commit log disk flush won't happen
-                        .run("sed -i -e \"s/commitlog_sync_period_in_ms: 10000/commitlog_sync_period_in_ms: 9999999/\" " + CASSANDRA_YAML)
-                        //auto_bootstrap should be useless when no existing data
-                        .run("echo auto_bootstrap: false >> " + CASSANDRA_YAML)
-                        .run("echo \"-Xms1500M\" >> " + JVM_OPTIONS)
-                        .run("echo \"-Xmx1500M\" >> " + JVM_OPTIONS)
-                        // disable assertions (modest performance benefit)
-                        .run("sed -i -e 's/JVM_OPTS=\"$JVM_OPTS -ea\"/JVM_OPTS=\"$JVM_OPTS -da\"/' " + CASSANDRA_ENV)
-                        // use caches for keys & rows
-                        .run("sed -i -e \"s/key_cache_size_in_mb:/key_cache_size_in_mb: 256/\" " + CASSANDRA_YAML)
-                        .run("sed -i -e \"s/row_cache_size_in_mb: 0/row_cache_size_in_mb: 512/\" " + CASSANDRA_YAML)
-                        .build()))
-            .withCreateContainerCmdModifier(cmd -> cmd.withMemory(2000 * 1024 * 1024L))
-            .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig().withTmpFs(ImmutableMap.of("/var/lib/cassandra", "rw,noexec,nosuid,size=100m")))
-            .withExposedPorts(CASSANDRA_PORT)
-            .withLogConsumer(this::displayDockerLog);
-        cassandraContainer
-            .waitingFor(new CassandraWaitStrategy(cassandraContainer));
-    }
-
-    private void displayDockerLog(OutputFrame outputFrame) {
-        logger.info(outputFrame.getUtf8String());
-    }
-
     @Override
     public Statement apply(Statement base, Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                cassandraContainer.apply(base, description).evaluate();
-            }
-        };
+        return base;
     }
 
     public void start() {
-        cassandraContainer.start();
+
     }
 
     public void stop() {
-        cassandraContainer.stop();
+
     }
 
     public Host getHost() {
-        return Host.from(
-            getIp(),
-            getBindingPort());
+        return DockerCassandraSingleton.singleton.getHost();
     }
     
     public String getIp() {
-        return cassandraContainer.getContainerIpAddress();
+        return DockerCassandraSingleton.singleton.getIp();
     }
 
     public int getBindingPort() {
-        return cassandraContainer.getMappedPort(CASSANDRA_PORT);
+        return DockerCassandraSingleton.singleton.getBindingPort();
     }
 
     public GenericContainer<?> getRawContainer() {
-        return cassandraContainer;
+        return DockerCassandraSingleton.singleton.getRawContainer();
     }
 
     public void pause() {
-        client.pauseContainerCmd(cassandraContainer.getContainerId());
+        DockerCassandraSingleton.singleton.pause();
     }
 
     public void unpause() {
-        client.unpauseContainerCmd(cassandraContainer.getContainerId());
+        DockerCassandraSingleton.singleton.unpause();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraSingleton.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraSingleton.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraSingleton.java
new file mode 100644
index 0000000..98fc5fc
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraSingleton.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * 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.backends.cassandra;
+
+public class DockerCassandraSingleton {
+
+    public static final DockerCassandra singleton = new DockerCassandra();
+
+    static {
+        singleton.start();
+    }
+
+    public static void restart() {
+        singleton.stop();
+        singleton.start();
+    }
+
+    // Cleanup will be performed by test container resource reaper
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/mailbox/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index fb1c5aa..26d57cf 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -176,4 +176,16 @@
         </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
index a273fb4..c7d6e7d 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
@@ -29,6 +29,7 @@ import javax.mail.Flags.Flag;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.DockerCassandraRule;
+import org.apache.james.backends.cassandra.DockerCassandraSingleton;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
@@ -57,6 +58,7 @@ public class CassandraMessageIdToImapUidDAOTest {
 
     @BeforeClass
     public static void setUpClass() {
+        DockerCassandraSingleton.restart();
         cassandra = CassandraCluster.create(CassandraMessageModule.MODULE, cassandraServer.getHost());
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/mpt/impl/imap-mailbox/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/imap-mailbox/cassandra/pom.xml b/mpt/impl/imap-mailbox/cassandra/pom.xml
index 2289877..4166a7c 100644
--- a/mpt/impl/imap-mailbox/cassandra/pom.xml
+++ b/mpt/impl/imap-mailbox/cassandra/pom.xml
@@ -60,4 +60,16 @@
             <artifactId>blob-cassandra</artifactId>
         </dependency>
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/mpt/impl/smtp/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/smtp/cassandra/pom.xml b/mpt/impl/smtp/cassandra/pom.xml
index 3942beb..04784de 100644
--- a/mpt/impl/smtp/cassandra/pom.xml
+++ b/mpt/impl/smtp/cassandra/pom.xml
@@ -92,5 +92,17 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
     
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/server/container/guice/cassandra-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/pom.xml b/server/container/guice/cassandra-guice/pom.xml
index af6166b..5035f68 100644
--- a/server/container/guice/cassandra-guice/pom.xml
+++ b/server/container/guice/cassandra-guice/pom.xml
@@ -333,6 +333,13 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/server/data/data-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/pom.xml b/server/data/data-cassandra/pom.xml
index 2e3eb96..3755ffa 100644
--- a/server/data/data-cassandra/pom.xml
+++ b/server/data/data-cassandra/pom.xml
@@ -158,6 +158,13 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
     

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/server/data/data-jmap-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-jmap-cassandra/pom.xml b/server/data/data-jmap-cassandra/pom.xml
index 201c98b..115ff7a 100644
--- a/server/data/data-jmap-cassandra/pom.xml
+++ b/server/data/data-jmap-cassandra/pom.xml
@@ -99,6 +99,13 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/server/mailrepository/mailrepository-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/pom.xml b/server/mailrepository/mailrepository-cassandra/pom.xml
index 69102d9..19f03d0 100644
--- a/server/mailrepository/mailrepository-cassandra/pom.xml
+++ b/server/mailrepository/mailrepository-cassandra/pom.xml
@@ -112,6 +112,13 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/524e43ab/server/protocols/webadmin-integration-test/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/pom.xml b/server/protocols/webadmin-integration-test/pom.xml
index 7ea2a82..6a02073 100644
--- a/server/protocols/webadmin-integration-test/pom.xml
+++ b/server/protocols/webadmin-integration-test/pom.xml
@@ -117,4 +117,16 @@
         </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[11/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
JAMES-2502 merge util and util-java8


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/630dcab1
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/630dcab1
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/630dcab1

Branch: refs/heads/master
Commit: 630dcab1ace49b8f8592c41a624a000964cec7ee
Parents: 136acc1
Author: Matthieu Baechler <ma...@apache.org>
Authored: Tue Jul 31 16:35:00 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:20:23 2018 +0200

----------------------------------------------------------------------
 backends-common/cassandra/pom.xml               |   4 +-
 backends-common/elasticsearch/pom.xml           |   2 +-
 core/pom.xml                                    |   5 -
 mailbox/api/pom.xml                             |   5 -
 mailbox/cassandra/pom.xml                       |   1 -
 mailbox/elasticsearch/pom.xml                   |   2 +-
 mailbox/jpa/pom.xml                             |   1 -
 mailbox/memory/pom.xml                          |   1 -
 mailbox/store/pom.xml                           |   4 -
 mailet/standard/pom.xml                         |   5 -
 mdn/pom.xml                                     |   2 +-
 mpt/impl/smtp/cassandra/pom.xml                 |   2 +-
 mpt/impl/smtp/core/pom.xml                      |   2 +-
 pom.xml                                         |  11 -
 protocols/imap/pom.xml                          |   5 -
 protocols/netty/pom.xml                         |   2 +-
 server/blob/blob-api/pom.xml                    |   2 +-
 server/blob/blob-cassandra/pom.xml              |   2 +-
 server/container/guice/cassandra-guice/pom.xml  |   2 +-
 .../guice/cassandra-ldap-guice/pom.xml          |   2 +-
 server/container/guice/guice-utils/pom.xml      |   2 +-
 server/container/mailbox-adapter/pom.xml        |   2 +-
 .../metrics/metrics-es-reporter/pom.xml         |   2 +-
 server/container/util-java8/pom.xml             | 110 ----
 .../org/apache/james/util/ClassLoaderUtils.java |  54 --
 .../james/util/CompletableFutureUtil.java       | 124 -----
 .../apache/james/util/FluentFutureStream.java   | 191 -------
 .../java/org/apache/james/util/GuavaUtils.java  |  37 --
 .../main/java/org/apache/james/util/Host.java   | 137 -----
 .../java/org/apache/james/util/MDCBuilder.java  | 147 ------
 .../apache/james/util/MDCStructuredLogger.java  |  50 --
 .../org/apache/james/util/MemoizedSupplier.java |  30 --
 .../org/apache/james/util/OptionalUtils.java    |  68 ---
 .../main/java/org/apache/james/util/Port.java   |  58 ---
 .../java/org/apache/james/util/Runnables.java   |  40 --
 .../java/org/apache/james/util/StreamUtils.java |  52 --
 .../org/apache/james/util/StructuredLogger.java |  30 --
 .../java/org/apache/james/util/ValuePatch.java  | 125 -----
 .../util/date/DefaultZonedDateTimeProvider.java |  31 --
 .../james/util/date/ImapDateTimeFormatter.java  |  94 ----
 .../james/util/date/ZonedDateTimeProvider.java  |  28 -
 .../util/mime/MessageContentExtractor.java      | 233 ---------
 .../apache/james/util/streams/Iterators.java    |  32 --
 .../james/util/streams/JamesCollectors.java     |  80 ---
 .../org/apache/james/util/streams/Limit.java    |  81 ---
 .../org/apache/james/util/streams/Offset.java   |  66 ---
 .../apache/james/util/CommutativityChecker.java |  58 ---
 .../james/util/CommutativityCheckerTest.java    | 101 ----
 .../james/util/CompletableFutureUtilTest.java   | 424 ---------------
 .../james/util/FluentFutureStreamTest.java      | 258 ----------
 .../org/apache/james/util/GuavaUtilsTest.java   |  80 ---
 .../java/org/apache/james/util/HostTest.java    | 219 --------
 .../org/apache/james/util/MDCBuilderTest.java   | 138 -----
 .../apache/james/util/MemoizedSupplierTest.java |  84 ---
 .../apache/james/util/OptionalUtilsTest.java    | 243 ---------
 .../java/org/apache/james/util/PortTest.java    |  92 ----
 .../org/apache/james/util/StreamUtilsTest.java  | 115 -----
 .../org/apache/james/util/ValuePatchTest.java   | 220 --------
 .../util/date/ImapDateTimeFormatterTest.java    | 252 ---------
 .../util/mime/MessageContentExtractorTest.java  | 514 -------------------
 .../util/streams/ImmutableCollectorsTest.java   | 123 -----
 .../james/util/streams/IteratorsTest.java       |  58 ---
 .../james/util/streams/JamesCollectorsTest.java | 121 -----
 .../apache/james/util/streams/LimitTest.java    | 115 -----
 .../apache/james/util/streams/OffsetTest.java   |  58 ---
 .../test/resources/testcontainers.properties    |   4 -
 server/container/util/pom.xml                   |  26 +
 .../org/apache/james/util/ClassLoaderUtils.java |  54 ++
 .../james/util/CompletableFutureUtil.java       | 124 +++++
 .../apache/james/util/FluentFutureStream.java   | 191 +++++++
 .../java/org/apache/james/util/GuavaUtils.java  |  37 ++
 .../main/java/org/apache/james/util/Host.java   | 137 +++++
 .../java/org/apache/james/util/MDCBuilder.java  | 147 ++++++
 .../apache/james/util/MDCStructuredLogger.java  |  50 ++
 .../org/apache/james/util/MemoizedSupplier.java |  30 ++
 .../org/apache/james/util/OptionalUtils.java    |  68 +++
 .../main/java/org/apache/james/util/Port.java   |  58 +++
 .../java/org/apache/james/util/Runnables.java   |  40 ++
 .../java/org/apache/james/util/StreamUtils.java |  52 ++
 .../org/apache/james/util/StructuredLogger.java |  30 ++
 .../java/org/apache/james/util/ValuePatch.java  | 125 +++++
 .../util/date/DefaultZonedDateTimeProvider.java |  31 ++
 .../james/util/date/ImapDateTimeFormatter.java  |  94 ++++
 .../james/util/date/ZonedDateTimeProvider.java  |  28 +
 .../util/mime/MessageContentExtractor.java      | 233 +++++++++
 .../apache/james/util/streams/Iterators.java    |  32 ++
 .../james/util/streams/JamesCollectors.java     |  80 +++
 .../org/apache/james/util/streams/Limit.java    |  81 +++
 .../org/apache/james/util/streams/Offset.java   |  66 +++
 .../apache/james/util/CommutativityChecker.java |  58 +++
 .../james/util/CommutativityCheckerTest.java    | 102 ++++
 .../james/util/CompletableFutureUtilTest.java   | 424 +++++++++++++++
 .../james/util/FluentFutureStreamTest.java      | 258 ++++++++++
 .../org/apache/james/util/GuavaUtilsTest.java   |  81 +++
 .../java/org/apache/james/util/HostTest.java    | 219 ++++++++
 .../org/apache/james/util/MDCBuilderTest.java   | 139 +++++
 .../apache/james/util/MemoizedSupplierTest.java |  84 +++
 .../apache/james/util/OptionalUtilsTest.java    | 243 +++++++++
 .../java/org/apache/james/util/PortTest.java    |  92 ++++
 .../org/apache/james/util/StreamUtilsTest.java  | 115 +++++
 .../org/apache/james/util/ValuePatchTest.java   | 220 ++++++++
 .../util/date/ImapDateTimeFormatterTest.java    | 252 +++++++++
 .../util/mime/MessageContentExtractorTest.java  | 514 +++++++++++++++++++
 .../util/streams/ImmutableCollectorsTest.java   | 123 +++++
 .../james/util/streams/IteratorsTest.java       |  58 +++
 .../james/util/streams/JamesCollectorsTest.java | 121 +++++
 .../apache/james/util/streams/LimitTest.java    | 115 +++++
 .../apache/james/util/streams/OffsetTest.java   |  58 +++
 server/data/data-jmap/pom.xml                   |   2 +-
 .../data/data-ldap-integration-testing/pom.xml  |   2 +-
 server/mailet/integration-testing/pom.xml       |   2 +-
 server/mailet/mailetcontainer-camel/pom.xml     |   2 +-
 .../cassandra-jmap-integration-testing/pom.xml  |   6 -
 .../jmap-integration-testing-common/pom.xml     |   6 -
 .../memory-jmap-integration-testing/pom.xml     |   6 -
 server/protocols/jmap/pom.xml                   |   6 +-
 server/protocols/protocols-imap4/pom.xml        |   2 +-
 server/protocols/protocols-managesieve/pom.xml  |   2 +-
 server/protocols/webadmin/webadmin-core/pom.xml |   2 +-
 server/protocols/webadmin/webadmin-data/pom.xml |   2 +-
 .../protocols/webadmin/webadmin-mailbox/pom.xml |   2 +-
 .../webadmin/webadmin-mailrepository/pom.xml    |   2 +-
 server/queue/queue-rabbitmq/pom.xml             |   2 +-
 server/task/pom.xml                             |   2 +-
 server/testing/pom.xml                          |   2 +-
 125 files changed, 5119 insertions(+), 5264 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/backends-common/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/pom.xml b/backends-common/cassandra/pom.xml
index 1b16ea0..675bae5 100644
--- a/backends-common/cassandra/pom.xml
+++ b/backends-common/cassandra/pom.xml
@@ -45,11 +45,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/backends-common/elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/pom.xml b/backends-common/elasticsearch/pom.xml
index bf4ba84..02af1ed 100644
--- a/backends-common/elasticsearch/pom.xml
+++ b/backends-common/elasticsearch/pom.xml
@@ -30,7 +30,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 0f533dc..ba3bce5 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -39,11 +39,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/api/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/api/pom.xml b/mailbox/api/pom.xml
index d136e63..9081a9b 100644
--- a/mailbox/api/pom.xml
+++ b/mailbox/api/pom.xml
@@ -39,11 +39,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index dd20476..fb1c5aa 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -84,7 +84,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/pom.xml b/mailbox/elasticsearch/pom.xml
index b9563c9..193e472 100644
--- a/mailbox/elasticsearch/pom.xml
+++ b/mailbox/elasticsearch/pom.xml
@@ -86,7 +86,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/jpa/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/jpa/pom.xml b/mailbox/jpa/pom.xml
index b9b0e64..45b057f 100644
--- a/mailbox/jpa/pom.xml
+++ b/mailbox/jpa/pom.xml
@@ -65,7 +65,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/memory/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/memory/pom.xml b/mailbox/memory/pom.xml
index ffee6aa..f8616f3 100644
--- a/mailbox/memory/pom.xml
+++ b/mailbox/memory/pom.xml
@@ -55,7 +55,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailbox/store/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/store/pom.xml b/mailbox/store/pom.xml
index 8c45a55..8033192 100644
--- a/mailbox/store/pom.xml
+++ b/mailbox/store/pom.xml
@@ -69,10 +69,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>metrics-api</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mailet/standard/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/standard/pom.xml b/mailet/standard/pom.xml
index d0dc22b..e0de349 100644
--- a/mailet/standard/pom.xml
+++ b/mailet/standard/pom.xml
@@ -53,11 +53,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mdn/pom.xml
----------------------------------------------------------------------
diff --git a/mdn/pom.xml b/mdn/pom.xml
index f04a46d..d925395 100644
--- a/mdn/pom.xml
+++ b/mdn/pom.xml
@@ -37,7 +37,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mpt/impl/smtp/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/smtp/cassandra/pom.xml b/mpt/impl/smtp/cassandra/pom.xml
index e38c657..3942beb 100644
--- a/mpt/impl/smtp/cassandra/pom.xml
+++ b/mpt/impl/smtp/cassandra/pom.xml
@@ -69,7 +69,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/mpt/impl/smtp/core/pom.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/smtp/core/pom.xml b/mpt/impl/smtp/core/pom.xml
index 045de64..8489164 100644
--- a/mpt/impl/smtp/core/pom.xml
+++ b/mpt/impl/smtp/core/pom.xml
@@ -53,7 +53,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2007c5f..de9542f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1522,17 +1522,6 @@
             </dependency>
             <dependency>
                 <groupId>${james.groupId}</groupId>
-                <artifactId>james-server-util-java8</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>${james.groupId}</groupId>
-                <artifactId>james-server-util-java8</artifactId>
-                <version>${project.version}</version>
-                <type>test-jar</type>
-            </dependency>
-            <dependency>
-                <groupId>${james.groupId}</groupId>
                 <artifactId>james-server-webadmin</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/protocols/imap/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml
index a14726a..484cfe4 100644
--- a/protocols/imap/pom.xml
+++ b/protocols/imap/pom.xml
@@ -59,11 +59,6 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/protocols/netty/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/netty/pom.xml b/protocols/netty/pom.xml
index 062a2cb..7161638 100644
--- a/protocols/netty/pom.xml
+++ b/protocols/netty/pom.xml
@@ -35,7 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.protocols.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/blob/blob-api/pom.xml
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/pom.xml b/server/blob/blob-api/pom.xml
index 9ebf1cf..8eba84b 100644
--- a/server/blob/blob-api/pom.xml
+++ b/server/blob/blob-api/pom.xml
@@ -35,7 +35,7 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/blob/blob-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/server/blob/blob-cassandra/pom.xml b/server/blob/blob-cassandra/pom.xml
index e99e241..af1456d 100644
--- a/server/blob/blob-cassandra/pom.xml
+++ b/server/blob/blob-cassandra/pom.xml
@@ -55,7 +55,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/guice/cassandra-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/pom.xml b/server/container/guice/cassandra-guice/pom.xml
index 77bd32b..af6166b 100644
--- a/server/container/guice/cassandra-guice/pom.xml
+++ b/server/container/guice/cassandra-guice/pom.xml
@@ -209,7 +209,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/guice/cassandra-ldap-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-ldap-guice/pom.xml b/server/container/guice/cassandra-ldap-guice/pom.xml
index 30b5382..3f14183 100644
--- a/server/container/guice/cassandra-ldap-guice/pom.xml
+++ b/server/container/guice/cassandra-ldap-guice/pom.xml
@@ -104,7 +104,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/guice/guice-utils/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-utils/pom.xml b/server/container/guice/guice-utils/pom.xml
index bed5d72..ce22975 100644
--- a/server/container/guice/guice-utils/pom.xml
+++ b/server/container/guice/guice-utils/pom.xml
@@ -35,7 +35,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>com.github.fge</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/mailbox-adapter/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/mailbox-adapter/pom.xml b/server/container/mailbox-adapter/pom.xml
index 8a8927a..8e3c338 100644
--- a/server/container/mailbox-adapter/pom.xml
+++ b/server/container/mailbox-adapter/pom.xml
@@ -86,7 +86,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/metrics/metrics-es-reporter/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/metrics/metrics-es-reporter/pom.xml b/server/container/metrics/metrics-es-reporter/pom.xml
index 89b5e4a..f989919 100644
--- a/server/container/metrics/metrics-es-reporter/pom.xml
+++ b/server/container/metrics/metrics-es-reporter/pom.xml
@@ -36,7 +36,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/util-java8/pom.xml b/server/container/util-java8/pom.xml
deleted file mode 100644
index 5a3e2d0..0000000
--- a/server/container/util-java8/pom.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?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/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.james</groupId>
-        <artifactId>james-server</artifactId>
-        <version>3.2.0-SNAPSHOT</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>james-server-util-java8</artifactId>
-    <name>Apache James :: Server :: Common Utilities :: Java 8</name>
-
-    <dependencies>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mime4j-dom</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.github.fge</groupId>
-            <artifactId>throwing-lambdas</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.github.steveash.guavate</groupId>
-            <artifactId>guavate</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.sun.mail</groupId>
-            <artifactId>javax.mail</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>javax.inject</groupId>
-            <artifactId>javax.inject</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>nl.jqno.equalsverifier</groupId>
-            <artifactId>equalsverifier</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.testcontainers</groupId>
-            <artifactId>testcontainers</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.github.dpaukov</groupId>
-            <artifactId>combinatoricslib3</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <reuseForks>true</reuseForks>
-                    <forkCount>1C</forkCount>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/ClassLoaderUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/ClassLoaderUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/ClassLoaderUtils.java
deleted file mode 100644
index 68d9b08..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/ClassLoaderUtils.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import javax.mail.util.SharedByteArrayInputStream;
-
-import org.apache.commons.io.IOUtils;
-
-public class ClassLoaderUtils {
-    public static String getSystemResourceAsString(String filename, Charset charset) {
-        try {
-            return IOUtils.toString(ClassLoader.getSystemResourceAsStream(filename), charset);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static String getSystemResourceAsString(String filename) {
-        return getSystemResourceAsString(filename, StandardCharsets.US_ASCII);
-    }
-
-    public static byte[] getSystemResourceAsByteArray(String filename) {
-        try {
-            return IOUtils.toByteArray(ClassLoader.getSystemResourceAsStream(filename));
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static SharedByteArrayInputStream getSystemResourceAsSharedStream(String filename) {
-        return new SharedByteArrayInputStream(getSystemResourceAsByteArray(filename));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/CompletableFutureUtil.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/CompletableFutureUtil.java b/server/container/util-java8/src/main/java/org/apache/james/util/CompletableFutureUtil.java
deleted file mode 100644
index d2e83af..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/CompletableFutureUtil.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-public class CompletableFutureUtil {
-
-    public static <T> CompletableFuture<Optional<T>> unwrap(CompletableFuture<Optional<CompletableFuture<T>>> base) {
-        return base.thenCompose(
-            optional -> optional.map(future -> future.thenApply(Optional::of))
-                .orElse(CompletableFuture.completedFuture(Optional.empty())));
-    }
-
-    @SafeVarargs
-    public static <T> CompletableFuture<Stream<T>> allOfArray(CompletableFuture<T>... futures) {
-        return allOf(Stream.of(futures));
-    }
-
-    public static <T, U, V> CompletableFuture<V> combine(CompletableFuture<T> t, CompletableFuture<U> u, BiFunction<T,U,V> combiner) {
-        return t.thenCompose(valueT ->
-            u.thenApply(valueU -> combiner.apply(valueT, valueU)));
-    }
-
-    public static <T> CompletableFuture<Stream<T>> allOf(Stream<CompletableFuture<T>> futureStream) {
-        return futureStream
-            .map((CompletableFuture<T> future) -> future.thenApply(Stream::of))
-            .parallel()
-            .reduce((future1, future2) ->
-            future1.thenCompose(
-                stream1 -> future2.thenCompose(
-                    stream2 -> {
-                        Stream<T> concatStream = Stream.concat(stream1, stream2);
-                        return CompletableFuture.completedFuture(concatStream);
-                    })))
-            .orElse(CompletableFuture.completedFuture(Stream.of()));
-    }
-
-    public static <R, T> CompletableFuture<Stream<R>> chainAll(Stream<T> futureStream,
-        Function<T, CompletableFuture<R>> transformationToChain) {
-        return futureStream
-            .map(t -> (Supplier<CompletableFuture<R>>) (() -> transformationToChain.apply(t)))
-            .reduce(CompletableFuture.<Stream<R>>completedFuture(Stream.of()),
-                (accumulator, supplier) ->
-                    accumulator.thenCompose(
-                        accumulatedStream ->
-                            supplier.get()
-                                .thenCompose(r ->
-                                    CompletableFuture.completedFuture(Stream.<R>concat(accumulatedStream, Stream.of(r))))
-                    ),
-                getCompletableFutureBinaryOperator());
-    }
-
-    private static <R> BinaryOperator<CompletableFuture<Stream<R>>> getCompletableFutureBinaryOperator() {
-        return (future1, future2) ->
-            future1.thenCompose(stream1 ->
-                future2.<Stream<R>>thenCompose(stream2 ->
-                    CompletableFuture.completedFuture(Stream.concat(stream1, stream2))));
-    }
-
-    public static <T> CompletableFuture<Stream<T>> performOnAll(CompletableFuture<Stream<T>> futurStream, Function<T, CompletableFuture<Void>> action) {
-        return thenComposeOnAll(futurStream, value ->
-            keepValue(() ->
-                action.apply(value),
-                value));
-    }
-
-    public static <T, U> CompletableFuture<Stream<U>> thenComposeOnAll(CompletableFuture<Stream<T>> futurStream, Function<T, CompletableFuture<U>> action) {
-        return futurStream
-            .thenCompose(stream ->
-                CompletableFutureUtil.allOf(
-                    stream.map(action)));
-    }
-
-    public static <T, U> CompletableFuture<Stream<U>> map(CompletableFuture<Stream<T>> futurStream, Function<T, U> action) {
-        return futurStream
-            .thenApply(stream ->
-                stream.map(action));
-    }
-
-    public static <T> CompletableFuture<Optional<T>> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream) {
-        return futureStream.thenApply(stream -> stream.reduce(binaryOperator));
-    }
-
-    public static <T> CompletableFuture<T> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream, T emptyAccumulator) {
-        return futureStream.thenApply(stream -> stream.reduce(binaryOperator).orElse(emptyAccumulator));
-    }
-
-    public static <T> CompletableFuture<T> keepValue(Supplier<CompletableFuture<Void>> supplier, T value) {
-        return supplier.get().thenApply(any -> value);
-    }
-
-    public static <T> Function<Boolean, CompletableFuture<Boolean>> composeIfTrue(Supplier<CompletableFuture<T>> composeOperation) {
-        return b -> {
-            if (b) {
-                return composeOperation.get().thenApply(any -> b);
-            }
-            return CompletableFuture.completedFuture(b);
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/FluentFutureStream.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/FluentFutureStream.java b/server/container/util-java8/src/main/java/org/apache/james/util/FluentFutureStream.java
deleted file mode 100644
index 9dcae7a..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/FluentFutureStream.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Collector;
-import java.util.stream.Stream;
-
-public class FluentFutureStream<T> {
-
-    private final CompletableFuture<Stream<T>> completableFuture;
-
-    /**
-     * Constructs a FluentFutureStream from a future of Stream.
-     */
-    public static <T> FluentFutureStream<T> of(CompletableFuture<Stream<T>> completableFuture) {
-        return new FluentFutureStream<>(completableFuture);
-    }
-
-    /**
-     * Constructs a FluentFutureStream from a Stream of Future
-     */
-    public static <T> FluentFutureStream<T> of(Stream<CompletableFuture<T>> completableFutureStream) {
-        return new FluentFutureStream<>(CompletableFutureUtil.allOf(completableFutureStream));
-    }
-
-    /**
-     * Constructs a FluentFutureStream from a Stream of Future of Stream.
-     *
-     * Underlying streams are flatMapped.
-     */
-    public static <T> FluentFutureStream<T> ofNestedStreams(Stream<CompletableFuture<Stream<T>>> completableFuture) {
-        return of(completableFuture)
-            .flatMap(Function.identity());
-    }
-
-    /**
-     * Constructs a FluentFutureStream from a Stream of Future of Optionals.
-     *
-     * Underlying optionals are unboxed.
-     */
-    public static <T> FluentFutureStream<T> ofOptionals(Stream<CompletableFuture<Optional<T>>> completableFuture) {
-        return of(completableFuture)
-            .flatMapOptional(Function.identity());
-    }
-
-    /**
-     * Constructs a FluentFutureStream from the supplied futures.
-     */
-    @SafeVarargs
-    public static <T> FluentFutureStream<T> ofFutures(CompletableFuture<T>... completableFutures) {
-        return new FluentFutureStream<>(CompletableFutureUtil.allOfArray(completableFutures));
-    }
-
-    private FluentFutureStream(CompletableFuture<Stream<T>> completableFuture) {
-        this.completableFuture = completableFuture;
-    }
-
-    /**
-     * For all values of the underlying stream, an action will be performed.
-     */
-    public FluentFutureStream<T> performOnAll(Function<T, CompletableFuture<Void>> action) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.performOnAll(completableFuture(), action));
-    }
-
-    /**
-     * Apply a transformation to all values of the underlying stream.
-     */
-    public <U> FluentFutureStream<U> map(Function<T, U> function) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.map(completableFuture(), function));
-    }
-
-    /**
-     * Apply a transformation to all value of the underlying stream.
-     *
-     * As the supplied transformation produces streams, the results will be flatMapped.
-     */
-    public <U> FluentFutureStream<U> flatMap(Function<T, Stream<U>> function) {
-        return FluentFutureStream.of(completableFuture().thenApply(stream ->
-            stream.flatMap(function)));
-    }
-
-    /**
-     * Apply a transformation to all value of the underlying stream.
-     *
-     * As the supplied transformation produces optionals, the results will be unboxed.
-     */
-    public <U> FluentFutureStream<U> flatMapOptional(Function<T, Optional<U>> function) {
-        return map(function)
-            .flatMap(OptionalUtils::toStream);
-    }
-
-    /**
-     * Apply a transformation to all value of the underlying stream.
-     *
-     * As the supplied transformation produces futures, we need to compose the returned values.
-     */
-    public <U> FluentFutureStream<U> thenComposeOnAll(Function<T, CompletableFuture<U>> function) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function));
-    }
-
-    /**
-     * Apply a transformation to all value of the underlying stream.
-     *
-     * As the supplied transformation produces futures of stream, we need to compose then flatMap the returned values.
-     */
-    public <U> FluentFutureStream<U> thenFlatCompose(Function<T, CompletableFuture<Stream<U>>> function) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function))
-            .flatMap(Function.identity());
-    }
-
-    /**
-     * Apply a transformation to all value of the underlying stream.
-     *
-     * As the supplied transformation produces futures of optionals, we need to compose then unbox the returned values.
-     */
-    public <U> FluentFutureStream<U> thenFlatComposeOnOptional(Function<T, CompletableFuture<Optional<U>>> function) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function))
-            .flatMapOptional(Function.identity());
-    }
-
-    /**
-     * Filter the values of the underlying stream.
-     */
-    public FluentFutureStream<T> filter(Predicate<T> predicate) {
-        return FluentFutureStream.of(completableFuture
-            .thenApply(stream -> stream.filter(predicate)));
-    }
-
-    /**
-     * Reduces the underlying stream. Reduced value is supplied as a Future of optional, as no empty value is supplied.
-     */
-    public CompletableFuture<Optional<T>> reduce(BinaryOperator<T> combiner) {
-        return CompletableFutureUtil.reduce(combiner, completableFuture);
-    }
-
-    /**
-     * educes the underlying stream. Reduced value is supplied as a Future, as an empty value is specified.
-     */
-    public CompletableFuture<T> reduce(T emptyAccumulator, BinaryOperator<T> combiner) {
-        return CompletableFutureUtil.reduce(combiner, completableFuture, emptyAccumulator);
-    }
-
-    /**
-     * Returns a future of the underlying stream.
-     */
-    public CompletableFuture<Stream<T>> completableFuture() {
-        return this.completableFuture;
-    }
-
-    /**
-     * Returns the future of the underlying collected stream.
-     */
-    public <C> CompletableFuture<C> collect(Collector<T, ?, C> collector) {
-        return this.completableFuture
-            .thenApply(stream -> stream.collect(collector));
-    }
-
-    /**
-     * Join and returns the underlying stream.
-     */
-    public Stream<T> join() {
-        return completableFuture().join();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
deleted file mode 100644
index 518ead1..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.lang3.tuple.Pair;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableListMultimap;
-
-public class GuavaUtils {
-    public static <K, V> ImmutableListMultimap<K, V> toMultimap(Map<K, List<V>> rights) {
-        return rights.entrySet()
-            .stream()
-            .flatMap(e -> e.getValue().stream().map(right -> Pair.of(e.getKey(), right)))
-            .collect(Guavate.toImmutableListMultimap(Pair::getKey, Pair::getValue));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/Host.java b/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
deleted file mode 100644
index cb6acce..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.List;
-import java.util.Optional;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-
-public class Host {
-
-    public static ImmutableList<Host> parseHosts(String hostsString) {
-        return parseHosts(hostsString, Optional.empty());
-    }
-
-    public static ImmutableList<Host> parseHosts(String hostsString, int defaultPort) {
-        return parseHosts(hostsString, Optional.of(defaultPort));
-    }
-
-    private static ImmutableList<Host> parseHosts(String hostsString, Optional<Integer> defaultPort) {
-        return Splitter.on(',')
-            .omitEmptyStrings()
-            .splitToList(hostsString)
-            .stream()
-            .map(string -> Host.parse(string, defaultPort))
-            .distinct()
-            .collect(Guavate.toImmutableList());
-    }
-
-    public static Host from(String hostname, int port) {
-        return new Host(hostname, port);
-    }
-
-    public static Host parseConfString(String ipAndPort, int defaultPort) {
-        return parse(ipAndPort, Optional.of(defaultPort));
-    }
-
-    public static Host parseConfString(String ipAndPort) {
-        return parse(ipAndPort, Optional.empty());
-    }
-
-    public static Host parse(String ipAndPort, Optional<Integer> defaultPort) {
-        Preconditions.checkNotNull(ipAndPort);
-        Preconditions.checkArgument(!ipAndPort.isEmpty());
-
-        List<String> parts = retrieveHostParts(ipAndPort);
-
-        String ip = parts.get(0);
-        int port = getPortFromConfPart(parts, defaultPort);
-
-        return new Host(ip, port);
-    }
-
-    private static List<String> retrieveHostParts(String ipAndPort) {
-        List<String> parts = Splitter.on(':')
-                .trimResults()
-                .splitToList(ipAndPort);
-
-        if (parts.size() < 1 || parts.size() > 2) {
-            throw new IllegalArgumentException(ipAndPort + " is not a valid cassandra node");
-        }
-        return parts;
-    }
-
-    private static int getPortFromConfPart(List<String> parts, Optional<Integer> defaultPort) {
-        if (parts.size() == 2) {
-            return Integer.valueOf(parts.get(1));
-        }
-        if (parts.size() == 1) {
-            return defaultPort.orElseThrow(() -> new IllegalArgumentException("Host do not have port part but no default port provided"));
-        }
-        throw new RuntimeException("A host should be either a hostname or a hostname and a port separated by a ':'");
-    }
-
-    private final String hostName;
-    private final int port;
-
-    @VisibleForTesting
-    Host(String hostName, int port) {
-        Preconditions.checkNotNull(hostName, "Hostname could not be null");
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(hostName), "Hostname could not be empty");
-        Port.assertValid(port);
-        this.hostName = hostName;
-        this.port = port;
-    }
-
-    public String getHostName() {
-        return hostName;
-    }
-
-    public int getPort() {
-        return port;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hashCode(hostName, port);
-    }
-
-    @Override
-    public final boolean equals(Object object) {
-        if (object instanceof Host) {
-            Host that = (Host) object;
-            return Objects.equal(this.hostName, that.hostName)
-                && Objects.equal(this.port, that.port);
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return this.hostName + ":" + this.port;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/MDCBuilder.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/MDCBuilder.java b/server/container/util-java8/src/main/java/org/apache/james/util/MDCBuilder.java
deleted file mode 100644
index e6709c8..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/MDCBuilder.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Supplier;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.MDC;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class MDCBuilder {
-
-    public interface VoidOperation {
-        void perform();
-    }
-
-    public static <T> T withMdc(MDCBuilder mdcBuilder, Supplier<T> answerSupplier) {
-        try (Closeable closeable = mdcBuilder.build()) {
-            try {
-                return answerSupplier.get();
-            } catch (RuntimeException e) {
-                LOGGER.error("Got error, logging its context", e);
-                throw e;
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static void withMdc(MDCBuilder mdcBuilder, VoidOperation logOperation) {
-        withMdc(mdcBuilder, () -> {
-            logOperation.perform();
-            return null;
-        });
-    }
-
-    public static final String HOST = "host";
-    public static final String IP = "ip";
-    public static final String PROTOCOL = "protocol";
-    public static final String USER = "user";
-    public static final String ACTION = "action";
-    public static final String SESSION_ID = "sessionId";
-    public static final String CHARSET = "charset";
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(MDCBuilder.class);
-
-    public static class Closeables implements Closeable {
-        private final List<Closeable> closeables;
-
-        public Closeables(List<Closeable> closeables) {
-            Preconditions.checkNotNull(closeables);
-            this.closeables = ImmutableList.copyOf(closeables);
-        }
-
-        @Override
-        public void close() throws IOException {
-            closeables.forEach(this::closeQuietly);
-        }
-
-        private void closeQuietly(Closeable closeable) {
-            try {
-                closeable.close();
-            } catch (IOException e) {
-                LOGGER.warn("Failed to close Closeable", e);
-            }
-        }
-    }
-
-    public static MDCBuilder create() {
-        return new MDCBuilder();
-    }
-
-    private final ImmutableMap.Builder<String, String> contextMap = ImmutableMap.builder();
-    private final ImmutableList.Builder<MDCBuilder> nestedBuilder = ImmutableList.builder();
-
-    private MDCBuilder() {}
-
-    public MDCBuilder addContext(MDCBuilder nested) {
-        this.nestedBuilder.add(nested);
-        return this;
-    }
-
-    public MDCBuilder addContext(String key, Object value) {
-        Preconditions.checkNotNull(key);
-        Optional.ofNullable(value)
-            .ifPresent(nonNullValue -> contextMap.put(key, nonNullValue.toString()));
-        return this;
-    }
-
-    @VisibleForTesting
-    Map<String, String> buildContextMap() {
-        return ImmutableMap.<String, String>builder()
-            .putAll(nestedBuilder.build()
-                .stream()
-                .map(MDCBuilder::buildContextMap)
-                .flatMap(map -> map.entrySet().stream())
-                .collect(Guavate.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)))
-            .putAll(contextMap.build())
-            .build();
-    }
-
-    public <T> T execute(Supplier<T> supplier) {
-        return MDCBuilder.withMdc(this, supplier);
-    }
-
-    public <T> Supplier<T> wrapArround(Supplier<T> supplier) {
-        return () -> execute(supplier);
-    }
-
-    public Closeable build() {
-        return new Closeables(
-            buildContextMap()
-                .entrySet()
-                .stream()
-                .map(entry -> MDC.putCloseable(entry.getKey(), entry.getValue()))
-                .collect(Guavate.toImmutableList()));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/MDCStructuredLogger.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/MDCStructuredLogger.java b/server/container/util-java8/src/main/java/org/apache/james/util/MDCStructuredLogger.java
deleted file mode 100644
index cf970ea..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/MDCStructuredLogger.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.function.Consumer;
-
-import org.slf4j.Logger;
-
-public class MDCStructuredLogger implements StructuredLogger {
-
-    public static MDCStructuredLogger forLogger(Logger logger) {
-        return new MDCStructuredLogger(logger);
-    }
-
-    private final Logger logger;
-    private final MDCBuilder mdcBuilder;
-
-    public MDCStructuredLogger(Logger logger) {
-        this.logger = logger;
-        this.mdcBuilder = MDCBuilder.create();
-    }
-
-    @Override
-    public StructuredLogger addField(String name, Object value) {
-        mdcBuilder.addContext(name, value);
-        return this;
-    }
-
-    @Override
-    public void log(Consumer<Logger> logOperation) {
-        MDCBuilder.withMdc(mdcBuilder, () -> logOperation.accept(logger));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/MemoizedSupplier.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/MemoizedSupplier.java b/server/container/util-java8/src/main/java/org/apache/james/util/MemoizedSupplier.java
deleted file mode 100644
index d0b4e3b..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/MemoizedSupplier.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.function.Supplier;
-
-import com.google.common.base.Suppliers;
-
-public class MemoizedSupplier {
-    public static <T> Supplier<T> of(Supplier<T> originalSupplier) {
-        return Suppliers.memoize(originalSupplier::get)::get;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
deleted file mode 100644
index 4a3449c..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-public class OptionalUtils {
-
-    @FunctionalInterface
-    public interface Operation {
-        void perform();
-    }
-
-    public static <T> Optional<T> executeIfEmpty(Optional<T> optional, Operation operation) {
-        if (!optional.isPresent()) {
-            operation.perform();
-        }
-        return optional;
-    }
-
-    public static <T> Stream<T> toStream(Optional<T> optional) {
-        return optional.map(Stream::of)
-            .orElse(Stream.of());
-    }
-
-    @SafeVarargs
-    public static <T> Optional<T> or(Optional<T>... optionals) {
-        return orStream(Arrays.stream(optionals));
-    }
-
-    @SafeVarargs
-    public static <T> Optional<T> orSuppliers(Supplier<Optional<T>>... suppliers) {
-        return orStream(Arrays.stream(suppliers)
-            .map(Supplier::get));
-    }
-
-    private static <T> Optional<T> orStream(Stream<Optional<T>> stream) {
-        return stream
-            .filter(Optional::isPresent)
-            .findFirst()
-            .orElse(Optional.empty());
-    }
-
-    public static <T> boolean containsDifferent(Optional<T> requestValue, T storeValue) {
-        return requestValue
-            .filter(value -> !value.equals(storeValue))
-            .isPresent();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/Port.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/Port.java b/server/container/util-java8/src/main/java/org/apache/james/util/Port.java
deleted file mode 100644
index 016c4b4..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/Port.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Random;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Range;
-
-public class Port {
-    public static final int MAX_PORT_VALUE = 65535;
-    public static final int PRIVILEGED_PORT_BOUND = 1024;
-    private static final Range<Integer> VALID_PORT_RANGE = Range.closed(1, MAX_PORT_VALUE);
-
-    public static int generateValidUnprivilegedPort() {
-        return new Random().nextInt(Port.MAX_PORT_VALUE - PRIVILEGED_PORT_BOUND) + PRIVILEGED_PORT_BOUND;
-    }
-
-    public static void assertValid(int port) {
-        Preconditions.checkArgument(isValid(port), "Port should be between 1 and 65535");
-    }
-
-    public static boolean isValid(int port) {
-        return VALID_PORT_RANGE.contains(port);
-    }
-
-    private final int value;
-
-    public Port(int value) {
-        validate(value);
-        this.value = value;
-    }
-
-    protected void validate(int port) {
-        assertValid(port);
-    }
-
-    public int getValue() {
-        return value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/Runnables.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/Runnables.java b/server/container/util-java8/src/main/java/org/apache/james/util/Runnables.java
deleted file mode 100644
index c199f31..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/Runnables.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Arrays;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Supplier;
-
-public class Runnables {
-    public static void runParallel(Runnable... runnables) {
-        FluentFutureStream.of(
-            Arrays.stream(runnables)
-                .map(runnable -> CompletableFuture.supplyAsync(toVoidSupplier(runnable))))
-            .join();
-    }
-
-    private static Supplier<Void> toVoidSupplier(Runnable runnable) {
-        return () -> {
-            runnable.run();
-            return null;
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
deleted file mode 100644
index e8a71bd..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
-public class StreamUtils {
-
-    public static <T> Stream<T> ofNullable(T[] array) {
-        return ofOptional(Optional.ofNullable(array));
-    }
-
-    public static <T> Stream<T> ofOptional(Optional<T[]> array) {
-        return array
-            .map(Arrays::stream)
-            .orElse(Stream.empty());
-    }
-
-    public static <T> Stream<T> flatten(Collection<Stream<T>> streams) {
-        return flatten(streams.stream());
-    }
-
-    public static <T> Stream<T> flatten(Stream<Stream<T>> streams) {
-        return streams.flatMap(Function.identity());
-    }
-
-    @SafeVarargs
-    public static <T> Stream<T> flatten(Stream<T>... streams) {
-        return flatten(Arrays.stream(streams));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/StructuredLogger.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/StructuredLogger.java b/server/container/util-java8/src/main/java/org/apache/james/util/StructuredLogger.java
deleted file mode 100644
index f6fcec4..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/StructuredLogger.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.function.Consumer;
-
-import org.slf4j.Logger;
-
-public interface StructuredLogger {
-    StructuredLogger addField(String name, Object value);
-
-    void log(Consumer<Logger> logOperation);
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/ValuePatch.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/ValuePatch.java b/server/container/util-java8/src/main/java/org/apache/james/util/ValuePatch.java
deleted file mode 100644
index 5c3d01a..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/ValuePatch.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Function;
-
-import com.google.common.base.Preconditions;
-
-public class ValuePatch<T> {
-
-    private enum State {
-        KEEP,
-        REMOVE,
-        MODIFY
-    }
-
-    public static <T> ValuePatch<T> modifyTo(T value) {
-        Preconditions.checkNotNull(value);
-        return new ValuePatch<>(value, State.MODIFY);
-    }
-
-    public static <T> ValuePatch<T> ofNullable(T value) {
-        return ofOptional(Optional.ofNullable(value));
-    }
-
-    public static <T> ValuePatch<T> ofOptional(Optional<T> value) {
-        Preconditions.checkNotNull(value);
-        return value.map(ValuePatch::modifyTo)
-            .orElse(ValuePatch.remove());
-    }
-
-    public static <T> ValuePatch<T> remove() {
-        return new ValuePatch<>(null, State.REMOVE);
-    }
-
-    public static <T> ValuePatch<T> keep() {
-        return new ValuePatch<>(null, State.KEEP);
-    }
-
-    private final T value;
-    private final State state;
-
-    private ValuePatch(T value, State state) {
-        this.value = value;
-        this.state = state;
-    }
-
-    public boolean isRemoved() {
-        return state == State.REMOVE;
-    }
-
-    public boolean isModified() {
-        return state == State.MODIFY;
-    }
-
-    public boolean isKept() {
-        return state == State.KEEP;
-    }
-
-    public <S> Optional<S> mapNotKeptToOptional(Function<Optional<T>, S> updateTransformation) {
-        if (isKept()) {
-            return Optional.empty();
-        }
-        return Optional.of(updateTransformation.apply(Optional.ofNullable(value)));
-    }
-
-    public T get() {
-        if (isModified()) {
-            return value;
-        } else {
-            throw new NoSuchElementException();
-        }
-    }
-
-    public Optional<T> notKeptOrElse(Optional<T> replacement) {
-        if (isKept()) {
-            return replacement;
-        }
-        return Optional.ofNullable(value);
-    }
-
-    public Optional<T> toOptional() {
-        return Optional.ofNullable(value);
-    }
-
-    public T getOrElse(T replacement) {
-        return toOptional().orElse(replacement);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof ValuePatch) {
-            ValuePatch<?> that = (ValuePatch<?>) o;
-            return Objects.equals(this.value, that.value) &&
-                Objects.equals(this.state, that.state);
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(value, state);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java b/server/container/util-java8/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
deleted file mode 100644
index 47b776a..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/****************************************************************
- * 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.util.date;
-
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-
-public class DefaultZonedDateTimeProvider implements ZonedDateTimeProvider {
-
-    @Override
-    public ZonedDateTime get() {
-        return ZonedDateTime.now(ZoneOffset.UTC);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util-java8/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java b/server/container/util-java8/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
deleted file mode 100644
index 0a0d633..0000000
--- a/server/container/util-java8/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************
- * 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.util.date;
-
-import static java.time.temporal.ChronoField.DAY_OF_MONTH;
-import static java.time.temporal.ChronoField.DAY_OF_WEEK;
-import static java.time.temporal.ChronoField.HOUR_OF_DAY;
-import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
-import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
-import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
-import static java.time.temporal.ChronoField.YEAR;
-
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeFormatterBuilder;
-import java.time.format.SignStyle;
-
-import com.google.common.collect.ImmutableMap;
-
-public class ImapDateTimeFormatter {
-
-    private static final int INITIAL_YEAR = 1970;
-
-    public static DateTimeFormatter rfc5322() {
-        return new DateTimeFormatterBuilder()
-                .parseCaseInsensitive()
-                .parseLenient()
-                .optionalStart()
-                    .appendText(DAY_OF_WEEK, dayOfWeek())
-                    .appendLiteral(", ")
-                .optionalEnd()
-                .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
-                .appendLiteral(' ')
-                .appendText(MONTH_OF_YEAR, monthOfYear())
-                .appendLiteral(' ')
-                .appendValueReduced(YEAR, 2, 4, INITIAL_YEAR)
-                .appendLiteral(' ')
-                .appendValue(HOUR_OF_DAY, 2)
-                .appendLiteral(':')
-                .appendValue(MINUTE_OF_HOUR, 2)
-                .optionalStart()
-                    .appendLiteral(':')
-                    .appendValue(SECOND_OF_MINUTE, 2)
-                .optionalEnd()
-                .appendLiteral(' ')
-                .appendOffset("+HHMM", "GMT")
-                .toFormatter();
-    }
-
-    private static ImmutableMap<Long, String> monthOfYear() {
-        return ImmutableMap.<Long, String>builder()
-                .put(1L, "Jan")
-                .put(2L, "Feb")
-                .put(3L, "Mar")
-                .put(4L, "Apr")
-                .put(5L, "May")
-                .put(6L, "Jun")
-                .put(7L, "Jul")
-                .put(8L, "Aug")
-                .put(9L, "Sep")
-                .put(10L, "Oct")
-                .put(11L, "Nov")
-                .put(12L, "Dec")
-                .build();
-    }
-
-    private static ImmutableMap<Long, String> dayOfWeek() {
-        return ImmutableMap.<Long, String>builder()
-                .put(1L, "Mon")
-                .put(2L, "Tue")
-                .put(3L, "Wed")
-                .put(4L, "Thu")
-                .put(5L, "Fri")
-                .put(6L, "Sat")
-                .put(7L, "Sun")
-                .build();
-    }
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[13/14] james-project git commit: MAILBOX-342 Avoid using static method for setting XML list separator

Posted by ma...@apache.org.
MAILBOX-342 Avoid using static method for setting XML list separator

It has an impact in property readers and makes some reuseForks tests to fails.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e3a3f475
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e3a3f475
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e3a3f475

Branch: refs/heads/master
Commit: e3a3f47504181b7e927350d0d1d49d33ad7cd041
Parents: 524e43a
Author: benwa <bt...@linagora.com>
Authored: Wed Aug 1 10:41:58 2018 +0700
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:32:02 2018 +0200

----------------------------------------------------------------------
 .../james/server/core/configuration/FileConfigurationProvider.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e3a3f475/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java b/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
index 9fe3ed6..3559d03 100644
--- a/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
+++ b/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
@@ -45,8 +45,8 @@ public class FileConfigurationProvider implements ConfigurationProvider {
     public static final HierarchicalConfiguration EMTY_CONFIGURATION = new HierarchicalConfiguration();
 
     public static XMLConfiguration getConfig(InputStream configStream) throws ConfigurationException {
-        XMLConfiguration.setDefaultListDelimiter(SEMICOLON);
         XMLConfiguration config = new XMLConfiguration();
+        config.setListDelimiter(SEMICOLON);
         config.setDelimiterParsingDisabled(true);
         config.setAttributeSplittingDisabled(true);
         config.load(configStream);


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[07/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java b/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
new file mode 100644
index 0000000..6f333cf
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
@@ -0,0 +1,424 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+
+public class CompletableFutureUtilTest {
+    private ExecutorService executorService;
+
+    @Before
+    public void setUp() {
+        executorService = Executors.newFixedThreadPool(4);
+    }
+
+    @After
+    public void tearDown() {
+        executorService.shutdownNow();
+    }
+
+    @Test
+    public void combineShouldReturnCombinationOfBothSuppliedFutures() {
+        int value1 = 18;
+        int value2 = 12;
+
+        assertThat(CompletableFutureUtil.combine(
+            CompletableFuture.completedFuture(value1),
+            CompletableFuture.completedFuture(value2),
+            (a, b) -> 2 * a + b)
+            .join())
+            .isEqualTo(2 * value1 + value2);
+
+    }
+
+    @Test
+    public void allOfShouldUnboxEmptyStream() {
+        assertThat(
+            CompletableFutureUtil.allOf(Stream.empty())
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void chainAllShouldPreserveExecutionOrder() {
+        int itemCount = 10;
+        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
+            .boxed()
+            .collect(Guavate.toImmutableList());
+
+        ConcurrentLinkedDeque<Integer> queue = new ConcurrentLinkedDeque<>();
+
+        CompletableFutureUtil.chainAll(ints.stream(),
+            i -> CompletableFuture.supplyAsync(() -> {
+                try {
+                    Thread.sleep(itemCount - i);
+                } catch (InterruptedException e) {
+                    throw Throwables.propagate(e);
+                }
+                queue.add(i);
+                return i;
+            }, executorService))
+            .join();
+
+        assertThat(queue)
+            .containsExactlyElementsOf(ints);
+    }
+
+    @Test
+    public void chainAllShouldNotThrowOnEmptyStream() {
+        Stream<Integer> result = CompletableFutureUtil.chainAll(Stream.<Integer>of(),
+            i -> CompletableFuture.supplyAsync(() -> i, executorService))
+            .join();
+
+        assertThat(result.collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void chainAllShouldPreserveOrder() {
+        int itemCount = 10;
+        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
+            .boxed()
+            .collect(Guavate.toImmutableList());
+
+        Stream<Integer> result = CompletableFutureUtil.chainAll(ints.stream(),
+            i -> CompletableFuture.supplyAsync(() -> i, executorService))
+            .join();
+
+        assertThat(result.collect(Guavate.toImmutableList()))
+            .containsExactlyElementsOf(ints);
+    }
+
+    @Test
+    public void allOfShouldUnboxStream() {
+        long value1 = 18L;
+        long value2 = 19L;
+        long value3 = 20L;
+        assertThat(
+            CompletableFutureUtil.allOf(
+                Stream.of(
+                    CompletableFuture.completedFuture(value1),
+                    CompletableFuture.completedFuture(value2),
+                    CompletableFuture.completedFuture(value3)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsOnly(value1, value2, value3);
+    }
+
+    @Test
+    public void allOfShouldPreserveOrder() {
+        long value1 = 18L;
+        long value2 = 19L;
+        long value3 = 20L;
+        long value4 = 21L;
+        long value5 = 22L;
+        long value6 = 23L;
+        long value7 = 24L;
+        long value8 = 25L;
+        long value9 = 26L;
+        long value10 = 27L;
+        assertThat(
+            CompletableFutureUtil.allOf(
+                Stream.of(
+                    CompletableFuture.completedFuture(value1),
+                    CompletableFuture.completedFuture(value2),
+                    CompletableFuture.completedFuture(value3),
+                    CompletableFuture.completedFuture(value4),
+                    CompletableFuture.completedFuture(value5),
+                    CompletableFuture.completedFuture(value6),
+                    CompletableFuture.completedFuture(value7),
+                    CompletableFuture.completedFuture(value8),
+                    CompletableFuture.completedFuture(value9),
+                    CompletableFuture.completedFuture(value10)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(value1, value2, value3, value4, value5, value6, value7, value8, value9, value10);
+    }
+
+    @Test
+    public void allOfArrayShouldPreserveOrder() {
+        long value1 = 18L;
+        long value2 = 19L;
+        long value3 = 20L;
+        long value4 = 21L;
+        long value5 = 22L;
+        long value6 = 23L;
+        long value7 = 24L;
+        long value8 = 25L;
+        long value9 = 26L;
+        long value10 = 27L;
+        assertThat(
+            CompletableFutureUtil.allOfArray(
+                    CompletableFuture.completedFuture(value1),
+                    CompletableFuture.completedFuture(value2),
+                    CompletableFuture.completedFuture(value3),
+                    CompletableFuture.completedFuture(value4),
+                    CompletableFuture.completedFuture(value5),
+                    CompletableFuture.completedFuture(value6),
+                    CompletableFuture.completedFuture(value7),
+                    CompletableFuture.completedFuture(value8),
+                    CompletableFuture.completedFuture(value9),
+                    CompletableFuture.completedFuture(value10))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(value1, value2, value3, value4, value5, value6, value7, value8, value9, value10);
+    }
+
+    @Test
+    public void allOfArrayShouldUnboxNoArgs() {
+        assertThat(
+            CompletableFutureUtil.allOfArray()
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void allOfArrayShouldUnboxArray() {
+        long value1 = 18L;
+        long value2 = 19L;
+        long value3 = 20L;
+        assertThat(
+            CompletableFutureUtil.allOfArray(
+                    CompletableFuture.completedFuture(value1),
+                    CompletableFuture.completedFuture(value2),
+                    CompletableFuture.completedFuture(value3))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsOnly(value1, value2, value3);
+    }
+
+    @Test
+    public void allOfShouldWorkOnVeryLargeStream() {
+        CompletableFutureUtil.allOf(
+            IntStream.range(0, 100000)
+                .boxed()
+                .map(CompletableFuture::completedFuture))
+            .join();
+    }
+
+    @Test
+    public void mapShouldMapOnStreamInsideACompletableFuturOfStream() {
+        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of(1, 2, 3));
+
+        assertThat(
+            CompletableFutureUtil.map(futurOfInteger, integer ->
+                integer * 2)
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 4, 6);
+    }
+
+    @Test
+    public void mapShouldReturnEmptyStreamWhenGivenAnEmptyStream() {
+        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of());
+
+        assertThat(
+            CompletableFutureUtil.map(futurOfInteger, integer ->
+                integer * 2)
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void thenComposeOnAllShouldMapOnStreamInsideACompletableFuturOfStreamAndTransformTheResultingStreamOfCompletableFutureIntoACompletableOfStreamAndFlatIt() {
+        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of(1, 2, 3));
+
+        assertThat(
+            CompletableFutureUtil.thenComposeOnAll(futurOfInteger, integer ->
+                CompletableFuture.completedFuture(integer * 2))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 4, 6);
+    }
+
+    @Test
+    public void thenComposeOnAllOnEmptyStreamShouldReturnAnEmptyStream() {
+        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of());
+
+        assertThat(
+            CompletableFutureUtil.thenComposeOnAll(futurOfInteger, integer ->
+                CompletableFuture.completedFuture(integer * 2))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void keepValueShouldCompleteWhenTheGivenCompletableFutureEnd() {
+        final AtomicInteger numOfFutureExecution = new AtomicInteger(0);
+
+        Supplier<CompletableFuture<Void>> future = () ->
+            CompletableFuture.runAsync(numOfFutureExecution::incrementAndGet);
+
+        assertThat(
+            CompletableFutureUtil.keepValue(future, 42)
+                .join())
+            .isEqualTo(42);
+
+        assertThat(
+            numOfFutureExecution.get())
+            .isEqualTo(1);
+    }
+
+    @Test
+    public void keepValueShouldReturnNullWithNullValue() {
+        Supplier<CompletableFuture<Void>> future = () ->
+            CompletableFuture.completedFuture(null);
+
+        assertThat(
+            CompletableFutureUtil.keepValue(future, null)
+                .join())
+            .isNull();
+    }
+
+    @Test
+    public void composeIfTrueShouldReturnTrueWhenTrue() {
+        assertThat(
+            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
+                .apply(true)
+                .join())
+            .isTrue();
+    }
+
+    @Test
+    public void composeIfTrueShouldReturnFalseWhenFalse() {
+        assertThat(
+            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
+                .apply(false)
+                .join())
+            .isFalse();
+    }
+
+    @Test
+    public void composeIfTrueShouldComposeWhenTrue() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+        CompletableFutureUtil.composeIfTrue(() -> {
+            atomicInteger.incrementAndGet();
+            return CompletableFuture.completedFuture(null);
+        })
+            .apply(true)
+            .join();
+
+        assertThat(atomicInteger.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void composeIfTrueShouldNotComposeWhenFalse() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+        CompletableFutureUtil.composeIfTrue(() -> {
+            atomicInteger.incrementAndGet();
+            return CompletableFuture.completedFuture(null);
+        })
+            .apply(false)
+            .join();
+
+        assertThat(atomicInteger.get()).isEqualTo(0);
+    }
+
+    @Test
+    public void reduceShouldReturnEmptyWhenNoValue() {
+        assertThat(
+            CompletableFutureUtil.reduce(
+                (i, j) -> i + j,
+                CompletableFutureUtil.<Long>allOfArray())
+                .join())
+            .isEmpty();
+    }
+
+    @Test
+    public void reduceShouldWork() {
+        assertThat(
+            CompletableFutureUtil.reduce(
+                (i, j) -> i + j,
+                CompletableFutureUtil.allOfArray(
+                    CompletableFuture.completedFuture(1L),
+                    CompletableFuture.completedFuture(2L),
+                    CompletableFuture.completedFuture(3L)
+                ))
+                .join())
+            .contains(6L);
+    }
+
+    @Test
+    public void reduceShouldReturnIdentityAccumulatorWhenNoValue() {
+        long identityAccumulator = 0L;
+        assertThat(
+            CompletableFutureUtil.reduce(
+                (i, j) -> i + j,
+                CompletableFutureUtil.<Long>allOfArray(),
+                identityAccumulator)
+                .join())
+            .isEqualTo(identityAccumulator);
+    }
+
+    @Test
+    public void reduceShouldWorkWithIdentityAccumulator() {
+        assertThat(
+            CompletableFutureUtil.reduce(
+                (i, j) -> i + j,
+                CompletableFutureUtil.allOfArray(
+                    CompletableFuture.completedFuture(1L),
+                    CompletableFuture.completedFuture(2L),
+                    CompletableFuture.completedFuture(3L)
+                ),
+                0L)
+                .join())
+            .isEqualTo(6L);
+    }
+
+    @Test
+    public void unwrapShouldUnwrapWhenValue() {
+        assertThat(
+            CompletableFutureUtil.unwrap(
+                    CompletableFuture.completedFuture(Optional.of(CompletableFuture.completedFuture(1L))))
+                .join())
+            .isEqualTo(Optional.of(1L));
+    }
+
+    @Test
+    public void unwrapShouldUnwrapWhenEmpty() {
+        assertThat(
+            CompletableFutureUtil.unwrap(
+                    CompletableFuture.completedFuture(Optional.empty()))
+                .join())
+            .isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java b/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
new file mode 100644
index 0000000..0877414
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
@@ -0,0 +1,258 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import com.github.steveash.guavate.Guavate;
+
+public class FluentFutureStreamTest {
+
+    @Test
+    public void ofFutureShouldConstructAFluentFutureStream() {
+        assertThat(
+            FluentFutureStream.ofFutures(
+                CompletableFuture.completedFuture(1),
+                CompletableFuture.completedFuture(2),
+                CompletableFuture.completedFuture(3))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void ofShouldConstructAFluentFutureStreamWhenProvidedAFutureOfStream() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void ofShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFuture() {
+        assertThat(
+            FluentFutureStream.of(
+                Stream.of(
+                    CompletableFuture.completedFuture(1),
+                    CompletableFuture.completedFuture(2),
+                    CompletableFuture.completedFuture(3)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void ofNestedStreamsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfStream() {
+        assertThat(
+            FluentFutureStream.ofNestedStreams(
+                Stream.of(
+                    CompletableFuture.completedFuture(Stream.of(1, 2)),
+                    CompletableFuture.completedFuture(Stream.of()),
+                    CompletableFuture.completedFuture(Stream.of(3))))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+
+    @Test
+    public void ofOptionalsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfOptionals() {
+        assertThat(
+            FluentFutureStream.ofOptionals(
+                Stream.of(
+                    CompletableFuture.completedFuture(Optional.of(1)),
+                    CompletableFuture.completedFuture(Optional.of(2)),
+                    CompletableFuture.completedFuture(Optional.empty()),
+                    CompletableFuture.completedFuture(Optional.of(3))))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void completableFutureShouldReturnAFutureOfTheUnderLayingStream() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .completableFuture()
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void mapShouldTransformUnderlyingValues() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .map(i -> i + 1)
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 3, 4);
+    }
+
+    @Test
+    public void flatMapShouldTransformUnderlyingValuesAndFlatMapResult() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .flatMap(i -> Stream.of(i, i + 1))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 2, 3, 3, 4);
+    }
+
+    @Test
+    public void flatMapOptionalShouldTransformUnderlyingValuesAndUnboxResult() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .flatMapOptional(i -> Optional.of(i + 1)
+                    .filter(j -> j % 2 == 0))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 4);
+    }
+
+    @Test
+    public void reduceShouldGatherAllValuesOfTheUnderlyingStream() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .reduce((a, b) -> a + b)
+                .join())
+            .contains(6);
+    }
+
+    @Test
+    public void reduceShouldGatherAllValuesOfTheUnderlyingStreamWithAnEmptyValue() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .reduce(0, (a, b) -> a + b)
+                .join())
+            .isEqualTo(6);
+    }
+
+    @Test
+    public void filterShouldBeAppliedOnTheUnderlyingStream() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .filter(i -> i % 2 == 1)
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 3);
+    }
+
+    @Test
+    public void thenComposeOnAllShouldTransformUnderlyingValuesAndComposeFutures() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .thenComposeOnAll(i -> CompletableFuture.completedFuture(i + 1))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 3, 4);
+    }
+
+    @Test
+    public void thenFlatComposeShouldTransformUnderlyingValuesAndComposeFuturesWithStreamUnboxing() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .thenFlatCompose(i -> CompletableFuture.completedFuture(Stream.of(i, i + 1)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 2, 3, 3, 4);
+    }
+
+    @Test
+    public void thenFlatComposeOnOptionalShouldTransformUnderlyingValuesAndComposeFuturesWithOptionalUnboxing() {
+        assertThat(
+            FluentFutureStream.of(
+                CompletableFuture.completedFuture(
+                    Stream.of(1, 2, 3)))
+                .thenFlatComposeOnOptional(i -> CompletableFuture.completedFuture(Optional.of(i + 1)
+                    .filter(j -> j % 2 == 0)))
+                .join()
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(2, 4);
+    }
+
+    @Test
+    public void thenPerformOnAllShouldGenerateASynchronousSideEffectForAllElementsOfTheUnderlyingStream() {
+        ConcurrentLinkedDeque<Integer> sideEffects = new ConcurrentLinkedDeque<>();
+
+        FluentFutureStream.of(
+            CompletableFuture.completedFuture(
+                Stream.of(1, 2, 3)))
+            .performOnAll(i -> {
+                sideEffects.addLast(i);
+                return CompletableFuture.completedFuture(null);
+            })
+            .join()
+            .collect(Guavate.toImmutableList());
+
+        assertThat(sideEffects).containsOnly(1, 2, 3);
+    }
+
+    @Test
+    public void collectShouldReturnTheCollectionOfData() {
+        assertThat(
+            FluentFutureStream.of(
+                Stream.of(
+                    CompletableFuture.completedFuture(1),
+                    CompletableFuture.completedFuture(2),
+                    CompletableFuture.completedFuture(3)))
+                .collect(Guavate.toImmutableList())
+                .join())
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void collectShouldReturnEmptyWhenStreamIsEmpty() {
+        assertThat(
+            FluentFutureStream.ofFutures()
+                .collect(Guavate.toImmutableList())
+                .join())
+            .isEmpty();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/GuavaUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/GuavaUtilsTest.java b/server/container/util/src/test/java/org/apache/james/util/GuavaUtilsTest.java
new file mode 100644
index 0000000..2d5a224
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/GuavaUtilsTest.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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+
+public class GuavaUtilsTest {
+
+    @Test
+    public void toMultimapShouldAcceptEmptyMaps() {
+        assertThat(GuavaUtils.toMultimap(ImmutableMap
+            .<String, List<String>>builder()
+            .build())
+            .asMap())
+            .isEqualTo(ImmutableMap.of());
+    }
+
+    @Test
+    public void toMultimapShouldAcceptSingleValuesMaps() {
+        assertThat(GuavaUtils.toMultimap(ImmutableMap
+            .<String, List<String>>builder()
+            .put("k1", ImmutableList.of("v1"))
+            .put("k2", ImmutableList.of("v2"))
+            .build())
+            .asMap())
+            .isEqualTo(ImmutableListMultimap.of(
+                "k1", "v1",
+                "k2", "v2")
+            .asMap());
+    }
+
+    @Test
+    public void toMultimapShouldAcceptMultiplesValuesMaps() {
+        assertThat(GuavaUtils.toMultimap(ImmutableMap
+            .<String, List<String>>builder()
+            .put("k1", ImmutableList.of("v1"))
+            .put("k2", ImmutableList.of("v2", "v2.1"))
+            .build())
+            .asMap())
+            .isEqualTo(ImmutableListMultimap.of(
+                "k1", "v1",
+                "k2", "v2",
+                "k2", "v2.1")
+                .asMap());
+    }
+
+    @Test
+    public void shouldStripEntriesWithEmptyList() {
+        assertThat(GuavaUtils.toMultimap(ImmutableMap
+            .<String, List<String>>builder()
+            .put("k1", ImmutableList.of())
+            .build())
+            .asMap())
+            .isEqualTo(ImmutableListMultimap.of().asMap());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/HostTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/HostTest.java b/server/container/util/src/test/java/org/apache/james/util/HostTest.java
new file mode 100644
index 0000000..3ebeaee
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/HostTest.java
@@ -0,0 +1,219 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class HostTest {
+
+    private static final int DEFAULT_PORT = 154;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void parseConfStringShouldParseConfWithIpAndPort() {
+        //Given
+        int expectedPort = 44;
+        String expectedIp = "142.145.254.111";
+        String ipAndPort = expectedIp + ":" + 44;
+
+        //When
+        Host actual = Host.parseConfString(ipAndPort);
+
+        //Then
+        assertThat(actual).isEqualTo(new Host(expectedIp, expectedPort));
+    }
+
+    @Test
+    public void parseConfStringShouldParseConfWithHostanmeAndPort() {
+        int expectedPort = 44;
+        String host = "host";
+
+        Host actual = Host.parseConfString(host + ":" + expectedPort);
+
+        assertThat(actual).isEqualTo(new Host(host, expectedPort));
+    }
+
+    @Test
+    public void parseConfStringShouldParseConfWithHostOnlyWhenDefaultPortIsProvided() {
+        //Given
+        String ipAndPort = "142.145.254.111";
+        String expectedIp = "142.145.254.111";
+
+        //When
+        Host actual = Host.parseConfString(ipAndPort, DEFAULT_PORT);
+
+        //Then
+        assertThat(actual).isEqualTo(new Host(expectedIp, DEFAULT_PORT));
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenConfigIsAnEmptyString() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        //Given
+        String ipAndPort = "";
+
+        //When
+        Host.parseConfString(ipAndPort);
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenOnlyHostnameAndNoDefaultPort() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        //Given
+        String hostname = "hostnameOnly";
+
+        //When
+        Host.parseConfString(hostname);
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenNegativePort() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        Host.parseConfString("host:-1");
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenZeroPort() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        Host.parseConfString("host:0");
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenTooHighPort() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        Host.parseConfString("host:65536");
+    }
+
+    @Test
+    public void parseConfStringShouldFailWhenConfigIsANullString() {
+        expectedException.expect(NullPointerException.class);
+
+        //Given
+        String ipAndPort = null;
+
+        //When
+        Host.parseConfString(ipAndPort);
+    }
+
+
+    @Test
+    public void parseConfStringShouldFailWhenConfigIsInvalid() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        //Given
+        String ipAndPort = "10.10.10.10:42:43";
+
+        //When
+        Host.parseConfString(ipAndPort);
+    }
+
+    @Test
+    public void parseHostsShouldParseEmptyString() {
+        assertThat(Host.parseHosts(""))
+            .isEmpty();
+    }
+
+    @Test
+    public void parseHostsShouldParseMonoHost() {
+        assertThat(Host.parseHosts("localhost:9200"))
+            .containsOnly(new Host("localhost", 9200));
+    }
+
+    @Test
+    public void parseHostsShouldParseMultiHosts() {
+        assertThat(Host.parseHosts("localhost:9200,server:9155"))
+            .containsOnly(
+                new Host("localhost", 9200),
+                new Host("server", 9155));
+    }
+
+    @Test
+    public void parseHostsShouldNotFailOnMultiComma() {
+        assertThat(Host.parseHosts("localhost:9200,,server:9155"))
+            .containsOnly(
+                new Host("localhost", 9200),
+                new Host("server", 9155));
+    }
+
+    @Test
+    public void parseHostsShouldFailOnInvalidHost() {
+        expectedException.expect(NumberFormatException.class);
+
+        Host.parseHosts("localhost:invalid,,server:9155");
+    }
+
+    @Test
+    public void parseHostsShouldSwallowDuplicates() {
+        assertThat(Host.parseHosts("localhost:9200,localhost:9200"))
+            .containsOnly(
+                new Host("localhost", 9200));
+    }
+
+    @Test
+    public void parseHostsShouldNotSwallowSameAddressDifferentPort() {
+        assertThat(Host.parseHosts("localhost:9200,localhost:9155"))
+            .containsOnly(
+                new Host("localhost", 9200),
+                new Host("localhost", 9155));
+    }
+
+    @Test
+    public void parseHostsShouldNotSwallowSamePortDifferentAddress() {
+        assertThat(Host.parseHosts("localhost:9200,abcd:9200"))
+            .containsOnly(
+                new Host("localhost", 9200),
+                new Host("abcd", 9200));
+    }
+
+    @Test
+    public void parseHostsShouldHandleDefaultPort() {
+        int defaultPort = 155;
+
+        assertThat(Host.parseHosts("localhost:9200,abcd", defaultPort))
+            .containsOnly(
+                new Host("localhost", 9200),
+                new Host("abcd", 155));
+    }
+
+    @Test
+    public void parseHostsShouldThrowOnAbsentPortWhenNoDefaultPort() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        Host.parseHosts("localhost:9200,abcd");
+    }
+
+    @Test
+    public void hostShouldRespectBeanContract() {
+        EqualsVerifier.forClass(Host.class).verify();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/MDCBuilderTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/MDCBuilderTest.java b/server/container/util/src/test/java/org/apache/james/util/MDCBuilderTest.java
new file mode 100644
index 0000000..bf09d1d
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/MDCBuilderTest.java
@@ -0,0 +1,139 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.collect.ImmutableList;
+
+public class MDCBuilderTest {
+
+    private static final String KEY_1 = "key1";
+    private static final String KEY_2 = "key2";
+    private static final String VALUE_1 = "value1";
+    private static final String VALUE_2 = "value2";
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void addContextShouldThrowOnNullKey() {
+        expectedException.expect(NullPointerException.class);
+
+        MDCBuilder.create()
+            .addContext(null, "any");
+    }
+
+    @Test
+    public void buildContextMapShouldReturnEmptyWhenNoContext() {
+        assertThat(MDCBuilder.create().buildContextMap())
+            .isEmpty();
+    }
+
+    @Test
+    public void buildContextMapShouldReturnContext() {
+        assertThat(
+            MDCBuilder.create()
+                .addContext(KEY_1, VALUE_1)
+                .addContext(KEY_2, VALUE_2)
+                .buildContextMap())
+            .containsOnlyKeys(KEY_1, KEY_2)
+            .containsEntry(KEY_1, VALUE_1)
+            .containsEntry(KEY_2, VALUE_2);
+    }
+
+    @Test
+    public void addContextShouldFilterOutNullValues() {
+        assertThat(
+            MDCBuilder.create()
+                .addContext(KEY_1, null)
+                .buildContextMap())
+            .isEmpty();
+    }
+
+    @Test
+    public void addContextShouldAllowRecursiveBuild() {
+        assertThat(
+            MDCBuilder.create()
+                .addContext(KEY_1, VALUE_1)
+                .addContext(MDCBuilder.create()
+                    .addContext(KEY_2, VALUE_2))
+                .buildContextMap())
+            .containsOnlyKeys(KEY_1, KEY_2)
+            .containsEntry(KEY_1, VALUE_1)
+            .containsEntry(KEY_2, VALUE_2);
+    }
+
+    @SuppressWarnings("resource")
+    @Test
+    public void closeablesConstructorShouldThrowOnNullList() {
+        expectedException.expect(NullPointerException.class);
+
+        new MDCBuilder.Closeables(null);
+    }
+
+    @Test
+    public void closeablesCloseShouldNotThrowWhenEmpty() throws IOException {
+        new MDCBuilder.Closeables(ImmutableList.of())
+            .close();
+    }
+
+    @Test
+    public void closeablesCloseShouldCallAllUnderlyingCloseables() throws IOException {
+        ImmutableList.Builder<String> builder = ImmutableList.builder();
+
+        Closeable closeable1 = () -> builder.add(VALUE_1);
+        Closeable closeable2 = () -> builder.add(VALUE_2);
+
+        new MDCBuilder.Closeables(
+            ImmutableList.of(closeable1, closeable2))
+            .close();
+
+        assertThat(builder.build())
+            .containsExactly(VALUE_1, VALUE_2);
+    }
+
+
+    @Test
+    public void closeablesCloseShouldCallAllUnderlyingCloseablesWhenError() throws IOException {
+        ImmutableList.Builder<String> builder = ImmutableList.builder();
+
+        Closeable closeable1 = () -> builder.add(VALUE_1);
+        Closeable closeable2 = () -> {
+            throw new IOException();
+        };
+        Closeable closeable3 = () -> builder.add(VALUE_2);
+
+        new MDCBuilder.Closeables(
+            ImmutableList.of(closeable1, closeable2, closeable3))
+            .close();
+
+        assertThat(builder.build())
+            .containsExactly(VALUE_1, VALUE_2);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/MemoizedSupplierTest.java b/server/container/util/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
new file mode 100644
index 0000000..e774354
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/MemoizedSupplierTest.java
@@ -0,0 +1,84 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import org.junit.Test;
+
+public class MemoizedSupplierTest {
+
+    @Test
+    public void getShouldReturnSuppliedValue() {
+        Supplier<Integer> supplier = MemoizedSupplier.of(() -> 42);
+
+        assertThat(supplier.get()).isEqualTo(42);
+    }
+
+    @Test
+    public void getShouldBeIdempotent() {
+        Supplier<Integer> supplier = MemoizedSupplier.of(() -> 42);
+
+        supplier.get();
+        assertThat(supplier.get()).isEqualTo(42);
+    }
+
+    @Test
+    public void nullValueShouldBeSupported() {
+        Supplier<Integer> supplier = MemoizedSupplier.of(() -> null);
+
+        supplier.get();
+        assertThat(supplier.get()).isNull();
+    }
+
+    @Test
+    public void underlyingSupplierShouldBeCalledOnlyOnce() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Supplier<Integer> supplier = MemoizedSupplier.of(() -> {
+            atomicInteger.incrementAndGet();
+            return 42;
+        });
+
+        supplier.get();
+        supplier.get();
+
+        assertThat(atomicInteger.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void underlyingSupplierShouldBeCalledOnlyOnceWhenReturningNullValue() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Supplier<Integer> supplier = MemoizedSupplier.of(() -> {
+            atomicInteger.incrementAndGet();
+            return null;
+        });
+
+        supplier.get();
+        supplier.get();
+
+        assertThat(atomicInteger.get()).isEqualTo(1);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/OptionalUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/OptionalUtilsTest.java b/server/container/util/src/test/java/org/apache/james/util/OptionalUtilsTest.java
new file mode 100644
index 0000000..17fe06e
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/OptionalUtilsTest.java
@@ -0,0 +1,243 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.github.steveash.guavate.Guavate;
+
+public class OptionalUtilsTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void ifEmptyShouldPreserveValueOfEmptyOptionals() {
+        Optional<Object> expected = OptionalUtils.executeIfEmpty(Optional.empty(), () -> { });
+
+        assertThat(expected).isEmpty();
+    }
+
+    @Test
+    public void ifEmptyShouldPreserveValueOfPresentOptionals() {
+        String value = "value";
+        Optional<String> expected = OptionalUtils.executeIfEmpty(Optional.of(value), () -> { });
+
+        assertThat(expected).contains(value);
+    }
+
+    @Test
+    public void ifEmptyShouldPerformOperationIfEmpty() {
+        AtomicInteger operationCounter = new AtomicInteger(0);
+
+        OptionalUtils.executeIfEmpty(Optional.empty(), operationCounter::incrementAndGet);
+
+        assertThat(operationCounter.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void ifEmptyShouldNotPerformOperationIfPresent() {
+        AtomicInteger operationCounter = new AtomicInteger(0);
+
+        OptionalUtils.executeIfEmpty(Optional.of("value"), operationCounter::incrementAndGet);
+
+        assertThat(operationCounter.get()).isEqualTo(0);
+    }
+
+    @Test
+    public void toStreamShouldConvertEmptyOptionalToEmptyStream() {
+        assertThat(
+            OptionalUtils.toStream(Optional.empty())
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void toStreamShouldConvertFullOptionalToStream() {
+        long value = 18L;
+        assertThat(
+            OptionalUtils.toStream(Optional.of(value))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(value);
+    }
+
+    @Test
+    public void orShouldReturnEmptyWhenNoParameter() {
+        assertThat(OptionalUtils.or())
+            .isEmpty();
+    }
+
+    @Test
+    public void orShouldReturnEmptyWhenEmpty() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.empty()))
+            .isEmpty();
+    }
+
+    @Test
+    public void orShouldReturnValueWhenValue() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.of(1)))
+            .contains(1);
+    }
+
+    @Test
+    public void orShouldReturnEmptyWhenBothEmpty() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.empty(),
+                Optional.empty()))
+            .isEmpty();
+    }
+
+    @Test
+    public void orShouldReturnFirstValueWhenOnlyFirstValue() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.of(18),
+                Optional.empty()))
+            .contains(18);
+    }
+
+    @Test
+    public void orShouldReturnSecondValueWhenOnlySecondValue() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.empty(),
+                Optional.of(18)))
+            .contains(18);
+    }
+
+    @Test
+    public void orShouldReturnFirstValueWhenBothValues() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.of(1),
+                Optional.of(2)))
+            .contains(1);
+    }
+
+    @Test
+    public void orShouldReturnThirdValueWhenOnlyThirdValue() {
+        assertThat(
+            OptionalUtils.or(
+                Optional.empty(),
+                Optional.empty(),
+                Optional.of(1)))
+            .contains(1);
+    }
+
+    @Test
+    public void orSuppliersShouldReturnEmptyWhenNoParameter() {
+        assertThat(OptionalUtils.or())
+            .isEmpty();
+    }
+
+    @Test
+    public void orSuppliersShouldReturnEmptyWhenEmpty() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                Optional::empty))
+            .isEmpty();
+    }
+
+    @Test
+    public void orSuppliersShouldReturnValueWhenValue() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                () -> Optional.of(1)))
+            .contains(1);
+    }
+
+    @Test
+    public void orSuppliersShouldReturnEmptyWhenBothEmpty() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                () -> Optional.empty(),
+                () -> Optional.empty()))
+            .isEmpty();
+    }
+
+    @Test
+    public void orSuppliersShouldReturnFirstValueWhenOnlyFirstValue() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                () -> Optional.of(18),
+                Optional::empty))
+            .contains(18);
+    }
+
+    @Test
+    public void orSuppliersShouldReturnSecondValueWhenOnlySecondValue() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                Optional::empty,
+                () -> Optional.of(18)))
+            .contains(18);
+    }
+
+    @Test
+    public void orSuppliersShouldReturnFirstValueWhenBothValues() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                () -> Optional.of(1),
+                () -> Optional.of(2)))
+            .contains(1);
+    }
+
+    @Test
+    public void orSuppliersShouldReturnThirdValueWhenOnlyThirdValue() {
+        assertThat(
+            OptionalUtils.orSuppliers(
+                Optional::empty,
+                Optional::empty,
+                () -> Optional.of(1)))
+            .contains(1);
+    }
+
+    @Test
+    public void containsDifferentShouldReturnTrueWhenNullStoreValue() throws Exception {
+        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), null)).isTrue();
+    }
+
+    @Test
+    public void containsDifferentShouldReturnFalseWhenEmpty() throws Exception {
+        assertThat(OptionalUtils.containsDifferent(Optional.empty(), "any")).isFalse();
+    }
+
+    @Test
+    public void containsDifferentShouldReturnFalseWhenSameValue() throws Exception {
+        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), "any")).isFalse();
+    }
+
+    @Test
+    public void containsDifferentShouldReturnTrueWhenDifferentValue() throws Exception {
+        assertThat(OptionalUtils.containsDifferent(Optional.of("any"), "other")).isTrue();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/PortTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/PortTest.java b/server/container/util/src/test/java/org/apache/james/util/PortTest.java
new file mode 100644
index 0000000..9d04204
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/PortTest.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Test;
+
+public class PortTest {
+    @Test
+    public void assertValidShouldThrowOnNegativePort() {
+        assertThatThrownBy(() -> Port.assertValid(-1))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void assertValidShouldThrowOnZeroPort() {
+        assertThatThrownBy(() -> Port.assertValid(0))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void assertValidShouldAcceptOne() {
+        Port.assertValid(1);
+    }
+
+    @Test
+    public void assertValidShouldAcceptMaxValue() {
+        Port.assertValid(Port.MAX_PORT_VALUE);
+    }
+
+    @Test
+    public void assertValidShouldThrowOnTooBigValue() {
+        assertThatThrownBy(() -> Port.assertValid(Port.MAX_PORT_VALUE + 1))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void isValidShouldReturnFalseWhenNegative() {
+        assertThat(Port.isValid(-1))
+            .isFalse();
+    }
+
+    @Test
+    public void isValidShouldReturnFalseWhenZero() {
+        assertThat(Port.isValid(0))
+            .isFalse();
+    }
+
+    @Test
+    public void isValidShouldReturnTrueWhenOne() {
+        assertThat(Port.isValid(1))
+            .isTrue();
+    }
+
+    @Test
+    public void isValidShouldReturnTrueWhenMaxValue() {
+        assertThat(Port.isValid(Port.MAX_PORT_VALUE))
+            .isTrue();
+    }
+
+    @Test
+    public void isValidShouldReturnFalseWhenAboveMaxValue() {
+        assertThat(Port.isValid(Port.MAX_PORT_VALUE + 1))
+            .isFalse();
+    }
+
+    @Test
+    public void generateValidUnprivilegedPortShouldReturnAValidPort() {
+        assertThat(Port.generateValidUnprivilegedPort())
+            .isBetween(Port.PRIVILEGED_PORT_BOUND, Port.MAX_PORT_VALUE);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/StreamUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/StreamUtilsTest.java b/server/container/util/src/test/java/org/apache/james/util/StreamUtilsTest.java
new file mode 100644
index 0000000..691c671
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/StreamUtilsTest.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+public class StreamUtilsTest {
+
+    @Test
+    public void flattenShouldReturnEmptyWhenEmptyStreams() {
+        assertThat(
+            StreamUtils.<Integer>flatten(ImmutableList.of())
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void flattenShouldPreserveSingleStreams() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2, 3)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void flattenShouldMergeSeveralStreamsTogether() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2, 3),
+                Stream.of(4, 5)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3, 4, 5);
+    }
+
+    @Test
+    public void flattenShouldAcceptEmptyStreams() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of()))
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void flattenShouldMergeEmptyStreamsWithOtherData() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2),
+                Stream.of(),
+                Stream.of(3)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void flattenShouldAcceptEmptyVarArg() {
+        assertThat(
+            StreamUtils.flatten()
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void flattenShouldThrowOnNullVarArg() {
+        Stream<String>[] streams = null;
+        assertThatThrownBy(() -> StreamUtils.flatten(streams).collect(Guavate.toImmutableList()))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void flattenShouldFlattenNonEmptyVarArg() {
+        assertThat(StreamUtils.flatten(Stream.of(1), Stream.of(2)).collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2);
+    }
+
+    @Test
+    public void ofNullableShouldReturnEmptyStreamWhenNull() {
+        assertThat(StreamUtils.ofNullable(null)
+            .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void ofNullableShouldReturnAStreamWithElementsOfTheArray() {
+        assertThat(StreamUtils.ofNullable(ImmutableList.of(1, 2).toArray())
+            .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/ValuePatchTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/ValuePatchTest.java b/server/container/util/src/test/java/org/apache/james/util/ValuePatchTest.java
new file mode 100644
index 0000000..ef84393
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/ValuePatchTest.java
@@ -0,0 +1,220 @@
+/****************************************************************
+ * 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 modifyTo 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+import org.junit.Test;
+
+public class ValuePatchTest {
+
+    public static final int REPLACEMENT_VALUE = 24;
+    public static final Optional<Integer> REPLACEMENT = Optional.of(REPLACEMENT_VALUE);
+    public static final int VALUE = 12;
+    public static final Optional<Integer> OPTIONAL_OF_VALUE = Optional.of(VALUE);
+
+    @Test
+    public void keepShouldProduceKeptValues() {
+        assertThat(ValuePatch.<Integer>keep().isKept()).isTrue();
+    }
+
+    @Test
+    public void keepShouldThrowOnGet() {
+        assertThatThrownBy(() -> ValuePatch.<Integer>keep().get()).isInstanceOf(NoSuchElementException.class);
+    }
+
+    @Test
+    public void keepShouldNotBeModified() {
+        assertThat(ValuePatch.<Integer>keep().isModified()).isFalse();
+    }
+
+    @Test
+    public void keepShouldNotBeRemoved() {
+        assertThat(ValuePatch.<Integer>keep().isRemoved()).isFalse();
+    }
+
+    @Test
+    public void removeShouldNotBeKept() {
+        assertThat(ValuePatch.<Integer>remove().isKept()).isFalse();
+    }
+
+    @Test
+    public void removeShouldBeRemoved() {
+        assertThat(ValuePatch.<Integer>remove().isRemoved()).isTrue();
+    }
+
+    @Test
+    public void removedShouldNotBeModified() {
+        assertThat(ValuePatch.<Integer>remove().isModified()).isFalse();
+    }
+
+    @Test
+    public void removeShouldThrowOnGet() {
+        assertThatThrownBy(() -> ValuePatch.<Integer>remove().get()).isInstanceOf(NoSuchElementException.class);
+    }
+
+    @Test
+    public void ofNullableShouldBeEquivalentToRemoveWhenNullParameter() {
+        assertThat(ValuePatch.<Integer>ofNullable(null)).isEqualTo(ValuePatch.<Integer>remove());
+    }
+
+    @Test
+    public void ofNullableShouldBeEquivalentToModifyWhenNonNullParameter() {
+        assertThat(ValuePatch.ofNullable(VALUE)).isEqualTo(ValuePatch.modifyTo(VALUE));
+    }
+
+    @Test
+    public void modifyToShouldNotBeKept() {
+        assertThat(ValuePatch.modifyTo(VALUE).isKept()).isFalse();
+    }
+
+    @Test
+    public void modifyToShouldNotBeRemoved() {
+        assertThat(ValuePatch.modifyTo(VALUE).isRemoved()).isFalse();
+    }
+
+    @Test
+    public void modifyToShouldBeModified() {
+        assertThat(ValuePatch.modifyTo(VALUE).isModified()).isTrue();
+    }
+
+    @Test
+    public void modifyToShouldThrowOnNullValue() {
+        assertThatThrownBy(() -> ValuePatch.modifyTo(null)).isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void modifyToShouldBeRetrievedByGet() {
+        assertThat(ValuePatch.modifyTo(VALUE).get()).isEqualTo(VALUE);
+    }
+
+    @Test
+    public void ofOptionalShouldThrowOnNullValue() {
+        assertThatThrownBy(() -> ValuePatch.ofOptional(null)).isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void ofOptionalShouldBeEquivalentToModifyToWhenPresent() {
+        assertThat(ValuePatch.ofOptional(OPTIONAL_OF_VALUE)).isEqualTo(ValuePatch.modifyTo(VALUE));
+    }
+
+    @Test
+    public void ofOptionalShouldBeEquivalentToRemoveWhenEmpty() {
+        assertThat(ValuePatch.ofOptional(Optional.empty())).isEqualTo(ValuePatch.remove());
+    }
+
+    @Test
+    public void notKeptOrElseShouldReturnElseWhenKept() {
+        assertThat(ValuePatch.<Integer>keep().notKeptOrElse(REPLACEMENT)).isEqualTo(REPLACEMENT);
+    }
+
+    @Test
+    public void notKeptOrElseShouldReturnEmptyWhenRemoved() {
+        assertThat(ValuePatch.<Integer>remove().notKeptOrElse(REPLACEMENT)).isEqualTo(Optional.empty());
+    }
+
+    @Test
+    public void notKeptOrElseShouldReturnOptionalWhenModified() {
+        assertThat(ValuePatch.modifyTo(VALUE).notKeptOrElse(REPLACEMENT)).isEqualTo(OPTIONAL_OF_VALUE);
+    }
+
+    @Test
+    public void toOptionalShouldReturnElseWhenKept() {
+        assertThat(ValuePatch.<Integer>keep().toOptional()).isEqualTo(Optional.empty());
+    }
+
+    @Test
+    public void toOptionalShouldReturnEmptyWhenRemoved() {
+        assertThat(ValuePatch.<Integer>remove().toOptional()).isEqualTo(Optional.empty());
+    }
+
+    @Test
+    public void toOptionalShouldReturnOptionalWhenModified() {
+        assertThat(ValuePatch.modifyTo(VALUE).toOptional()).isEqualTo(OPTIONAL_OF_VALUE);
+    }
+
+    @Test
+    public void getOrElseShouldReturnReplacementWhenKept() {
+        assertThat(ValuePatch.<Integer>keep().getOrElse(REPLACEMENT_VALUE)).isEqualTo(REPLACEMENT_VALUE);
+    }
+
+    @Test
+    public void getOrElseShouldReturnReplacementWhenRemoved() {
+        assertThat(ValuePatch.<Integer>remove().getOrElse(REPLACEMENT_VALUE)).isEqualTo(REPLACEMENT_VALUE);
+    }
+
+    @Test
+    public void getOrElseShouldReturnValueWhenPresent() {
+        assertThat(ValuePatch.modifyTo(VALUE).getOrElse(REPLACEMENT_VALUE)).isEqualTo(VALUE);
+    }
+
+    @Test
+    public void getOrElseShouldReturnNullWhenKeptAndNullSpecified() {
+        assertThat(ValuePatch.<Integer>keep().getOrElse(null)).isNull();
+    }
+
+    @Test
+    public void getOrElseShouldReturnNullWhenRemovedAndNullSpecified() {
+        assertThat(ValuePatch.<Integer>remove().getOrElse(null)).isNull();
+    }
+
+    @Test
+    public void getOrElseShouldReturnValueWhenPresentAndNullSpecified() {
+        assertThat(ValuePatch.modifyTo(VALUE).getOrElse(null)).isEqualTo(VALUE);
+    }
+
+    @Test
+    public void mapNotKeptToValueShouldPreserveKept() {
+        assertThat(
+            ValuePatch.<Integer>keep()
+                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
+            .isEmpty();
+    }
+
+    @Test
+    public void mapNotKeptToValueShouldTransformOf() {
+        assertThat(
+            ValuePatch.modifyTo(VALUE)
+                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
+            .contains(VALUE + 1);
+    }
+
+    @Test
+    public void mapNotKeptToValueShouldTransformRemoved() {
+        assertThat(
+            ValuePatch.<Integer>remove()
+                .mapNotKeptToOptional(optional -> optional.map(i -> i + 1).orElse(REPLACEMENT_VALUE)))
+            .contains(REPLACEMENT_VALUE);
+    }
+
+    @Test
+    public void mapNotKeptToValueShouldThrowWhenNull() {
+        assertThatThrownBy(
+            () -> ValuePatch.modifyTo(12)
+                .mapNotKeptToOptional(any -> null)
+                .isPresent())
+            .isInstanceOf(NullPointerException.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java b/server/container/util/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
new file mode 100644
index 0000000..ec970fb
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/date/ImapDateTimeFormatterTest.java
@@ -0,0 +1,252 @@
+/****************************************************************
+ * 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.util.date;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.DayOfWeek;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeParseException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class ImapDateTimeFormatterTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void dayOfWeekShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getDayOfWeek()).isEqualTo(DayOfWeek.WEDNESDAY);
+    }
+
+    @Test
+    public void parseShouldNotThrowWhenDayOfWeekIsAbsent() {
+        ZonedDateTime.parse("28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenDayOfWeekIsWrong() {
+        expectedException.expect(DateTimeParseException.class);
+        // must be wednesday
+        ZonedDateTime.parse("Mon, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenDayOfWeekIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Abc, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void dayOfWeekShouldBeParsedWhenOneDigit() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getDayOfMonth()).isEqualTo(3);
+    }
+
+    @Test
+    public void dayOfWeekShouldBeParsedWhenTwoDigits() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("13 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getDayOfMonth()).isEqualTo(13);
+    }
+
+    @Test
+    public void parseShouldThrowWhenDayOfMonthIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenDayOfMonthIsNegative() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("-2 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenDayOfMonthIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("64 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void monthOfYearShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getMonth()).isEqualTo(Month.JUNE);
+    }
+
+    @Test
+    public void parseShouldThrowWhenMonthOfYearIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Wed, 28 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenMonthOfYearIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Wed, 28 Abc 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void yearShouldBeParsedWhenFourDigits() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("Wed, 28 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getYear()).isEqualTo(2017);
+    }
+
+    @Test
+    public void yearShouldBeParsedWhenTwoDigitsGreaterThanInitialYear() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("28 Jun 77 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getYear()).isEqualTo(1977);
+    }
+
+    @Test
+    public void yearShouldBeParsedWhenTwoDigitsLesserThanInitialYear() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("28 Jun 64 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getYear()).isEqualTo(2064);
+    }
+
+    @Test
+    public void parseShouldThrowWhenYearIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Wed, 28 Jun 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenYearIsLesserThanTwoDigits() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Wed, 28 Jun 1 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenYearIsGreaterThanFourDigits() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("Wed, 28 Jun 12345 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void hourOfDayShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getHour()).isEqualTo(4);
+    }
+
+    @Test
+    public void parseShouldNotThrowWhenHourOfDayIsLesserThanTwoDigits() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 4:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getHour()).isEqualTo(4);
+    }
+
+    @Test
+    public void parseShouldThrowWhenHourOfDayIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 :35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenHourOfDayIsGreaterThanTwoDigits() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 123:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenHourOfDayIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 48:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void minuteOfHourShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getMinute()).isEqualTo(35);
+    }
+
+    @Test
+    public void parseShouldNotThrowWhenMinuteOfHourIsLesserThanTwoDigits() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:5:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getMinute()).isEqualTo(5);
+    }
+
+    @Test
+    public void parseShouldThrowWhenMinuteOfHourIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04::11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenMinuteOfHourIsGreaterThanTwoDigits() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:123:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenMinuteOfHourDayIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:72:11 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void secondOfMinuteShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getSecond()).isEqualTo(11);
+    }
+
+    @Test
+    public void parseShouldNotThrowWhenSecondOfMinuteIsLesserThanTwoDigits() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:1 -0700", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getSecond()).isEqualTo(1);
+    }
+
+    @Test
+    public void parseShouldNotThrowWhenSecondOfMinuteIsAbsent() {
+        ZonedDateTime.parse("28 Jun 2017 04:35 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenSecondOfMinuteIsGreaterThanTwoDigits() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:35:123 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenSecondOfMinuteDayIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:35:78 -0700", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void offsetShouldBeParsed() {
+        ZonedDateTime dateTime = ZonedDateTime.parse("3 Jun 2017 04:35:11 -0712", ImapDateTimeFormatter.rfc5322());
+        assertThat(dateTime.getOffset()).isEqualTo(ZoneOffset.ofHoursMinutes(-7, -12));
+    }
+
+    @Test
+    public void parseShouldThrowWhenOffsetIsAbsent() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:35:11", ImapDateTimeFormatter.rfc5322());
+    }
+
+    @Test
+    public void parseShouldThrowWhenOffsetIsUnknow() {
+        expectedException.expect(DateTimeParseException.class);
+        ZonedDateTime.parse("3 Jun 2017 04:35:11 +7894", ImapDateTimeFormatter.rfc5322());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[14/14] james-project git commit: MAILBOX-342 Enforce static method for setting XML, properties list separator

Posted by ma...@apache.org.
MAILBOX-342 Enforce static method for setting XML, properties list separator

It has an impact in property readers and makes some reuseForks tests to fails.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5935abbb
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5935abbb
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5935abbb

Branch: refs/heads/master
Commit: 5935abbb7075325e36d470df5220b5c3b7a04095
Parents: e3a3f47
Author: benwa <bt...@linagora.com>
Authored: Wed Aug 1 11:46:03 2018 +0700
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:32:02 2018 +0200

----------------------------------------------------------------------
 .../cassandra/init/configuration/ClusterConfiguration.java        | 2 +-
 .../server/core/configuration/FileConfigurationProvider.java      | 3 ++-
 .../apache/james/modules/mailbox/ElasticSearchConfiguration.java  | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5935abbb/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
index a4731d8..aa9d8f6 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
@@ -176,7 +176,7 @@ public class ClusterConfiguration {
     }
 
     public static ClusterConfiguration from(PropertiesConfiguration configuration) {
-        configuration.setListDelimiter(',');
+        PropertiesConfiguration.setDefaultListDelimiter(',');
         return ClusterConfiguration.builder()
             .hosts(listCassandraServers(configuration))
             .keyspace(Optional.ofNullable(configuration.getString(CASSANDRA_KEYSPACE, null)))

http://git-wip-us.apache.org/repos/asf/james-project/blob/5935abbb/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java b/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
index 3559d03..911907e 100644
--- a/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
+++ b/server/container/core/src/main/java/org/apache/james/server/core/configuration/FileConfigurationProvider.java
@@ -26,6 +26,7 @@ import java.util.Optional;
 
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.commons.configuration.XMLConfiguration;
 import org.apache.james.filesystem.api.FileSystem;
 import org.slf4j.Logger;
@@ -45,8 +46,8 @@ public class FileConfigurationProvider implements ConfigurationProvider {
     public static final HierarchicalConfiguration EMTY_CONFIGURATION = new HierarchicalConfiguration();
 
     public static XMLConfiguration getConfig(InputStream configStream) throws ConfigurationException {
+        PropertiesConfiguration.setDefaultListDelimiter(SEMICOLON);
         XMLConfiguration config = new XMLConfiguration();
-        config.setListDelimiter(SEMICOLON);
         config.setDelimiterParsingDisabled(true);
         config.setAttributeSplittingDisabled(true);
         config.load(configStream);

http://git-wip-us.apache.org/repos/asf/james-project/blob/5935abbb/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
index b15b4d7..9332616 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
@@ -280,7 +280,7 @@ public class ElasticSearchConfiguration {
     }
 
     private static ImmutableList<Host> getHosts(PropertiesConfiguration propertiesReader) throws ConfigurationException {
-        propertiesReader.setListDelimiter(',');
+        PropertiesConfiguration.setDefaultListDelimiter(',');
         Optional<String> masterHost = Optional.ofNullable(
             propertiesReader.getString(ELASTICSEARCH_MASTER_HOST, null));
         Optional<Integer> masterPort = Optional.ofNullable(


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[05/14] james-project git commit: JAMES-2502 fix Eclipse Photon build for mailets, utils and imap

Posted by ma...@apache.org.
JAMES-2502 fix Eclipse Photon build for mailets, utils and imap


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3dddd7c5
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3dddd7c5
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3dddd7c5

Branch: refs/heads/master
Commit: 3dddd7c55025c6f91604cccce215873cdef223f1
Parents: 8d22e35
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Fri Jul 27 18:02:03 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Aug 1 14:20:23 2018 +0200

----------------------------------------------------------------------
 backends-common/elasticsearch/pom.xml           |   4 +-
 core/pom.xml                                    |   3 +-
 .../org/apache/james/util/MimeMessageUtil.java  |  55 --
 mailbox/elasticsearch/pom.xml                   |   5 +
 mailbox/plugin/quota-mailing-cassandra/pom.xml  |   5 +
 mailbox/plugin/quota-mailing-memory/pom.xml     |   5 +
 mailbox/plugin/quota-mailing/pom.xml            |   3 +-
 mailbox/tika/pom.xml                            |   3 +-
 mailet/base/pom.xml                             |   8 +-
 .../apache/mailet/base/MailAddressFixture.java  |  56 --
 .../org/apache/mailet/base/test/FakeMail.java   | 464 --------------
 .../mailet/base/test/FakeMailContext.java       | 608 -------------------
 .../apache/mailet/base/test/FakeMailTest.java   |  41 --
 .../mailet/base/test/FakeMailetConfig.java      | 106 ----
 .../mailet/base/test/FakeMatcherConfig.java     |  95 ---
 .../org/apache/mailet/base/test/MailUtil.java   |  92 ---
 mailet/icalendar/pom.xml                        |   3 +-
 mailet/pom.xml                                  |   1 +
 mailet/standard/pom.xml                         |   9 +-
 mailet/test/pom.xml                             | 138 +++++
 .../apache/mailet/base/MailAddressFixture.java  |  56 ++
 .../org/apache/mailet/base/test/FakeMail.java   | 464 ++++++++++++++
 .../mailet/base/test/FakeMailContext.java       | 608 +++++++++++++++++++
 .../mailet/base/test/FakeMailetConfig.java      | 106 ++++
 .../mailet/base/test/FakeMatcherConfig.java     |  95 +++
 .../org/apache/mailet/base/test/MailUtil.java   |  92 +++
 .../apache/mailet/base/test/FakeMailTest.java   |  41 ++
 mpt/impl/imap-mailbox/core/pom.xml              |   5 -
 pom.xml                                         |   5 +
 .../decode/ImapRequestStreamLineReader.java     | 105 ++++
 .../decode/main/ImapRequestStreamHandler.java   | 129 ++++
 .../main/OutputStreamImapResponseWriter.java    |  70 +++
 .../james/imap/encode/FakeImapSession.java      | 145 +++++
 .../decode/ImapRequestStreamLineReader.java     | 105 ----
 .../decode/main/ImapRequestStreamHandler.java   | 129 ----
 .../main/OutputStreamImapResponseWriter.java    |  70 ---
 .../james/imap/encode/FakeImapSession.java      | 145 -----
 server/container/core/pom.xml                   |   3 +-
 .../metrics/metrics-es-reporter/pom.xml         |   3 +-
 .../org/apache/james/util/docker/Images.java    |  29 -
 .../util/docker/SwarmGenericContainer.java      | 164 -----
 server/container/util/pom.xml                   |  14 +-
 .../org/apache/james/util/MimeMessageUtil.java  |  55 ++
 .../data/data-ldap-integration-testing/pom.xml  |   3 +-
 server/mailet/integration-testing/pom.xml       |   3 +-
 server/pom.xml                                  |   1 -
 server/protocols/jmap/pom.xml                   |   3 +-
 .../webadmin/webadmin-mailqueue/pom.xml         |   3 +-
 .../webadmin/webadmin-mailrepository/pom.xml    |   3 +-
 server/queue/queue-rabbitmq/pom.xml             |   3 +-
 server/testing/pom.xml                          |   3 +-
 .../org/apache/james/util/docker/Images.java    |  29 +
 .../util/docker/SwarmGenericContainer.java      | 164 +++++
 third-party/spamassassin/pom.xml                |   5 +
 54 files changed, 2358 insertions(+), 2204 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/backends-common/elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/pom.xml b/backends-common/elasticsearch/pom.xml
index 6d8d071..bf4ba84 100644
--- a/backends-common/elasticsearch/pom.xml
+++ b/backends-common/elasticsearch/pom.xml
@@ -34,9 +34,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
+            <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 600c567..0f533dc 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -38,8 +38,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>javax-mail-extension</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-util</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/javax-mail-extension/src/test/java/org/apache/james/util/MimeMessageUtil.java
----------------------------------------------------------------------
diff --git a/javax-mail-extension/src/test/java/org/apache/james/util/MimeMessageUtil.java b/javax-mail-extension/src/test/java/org/apache/james/util/MimeMessageUtil.java
deleted file mode 100644
index 93715f8..0000000
--- a/javax-mail-extension/src/test/java/org/apache/james/util/MimeMessageUtil.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************
- * 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.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Properties;
-
-import javax.mail.MessagingException;
-import javax.mail.Session;
-import javax.mail.internet.MimeMessage;
-
-public class MimeMessageUtil {
-
-    public static String asString(MimeMessage mimeMessage) throws Exception {
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        mimeMessage.writeTo(byteArrayOutputStream);
-        return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8);
-    }
-
-    public static MimeMessage defaultMimeMessage() {
-        return new MimeMessage(Session.getDefaultInstance(new Properties()));
-    }
-
-    public static MimeMessage mimeMessageFromStream(InputStream inputStream) throws MessagingException {
-        return new MimeMessage(Session.getDefaultInstance(new Properties()), inputStream);
-    }
-
-    public static MimeMessage mimeMessageFromBytes(byte[] bytes) throws MessagingException {
-        return mimeMessageFromStream(new ByteArrayInputStream(bytes));
-    }
-
-    public static MimeMessage mimeMessageFromString(String string) throws MessagingException {
-        return mimeMessageFromBytes(string.getBytes(StandardCharsets.UTF_8));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailbox/elasticsearch/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/pom.xml b/mailbox/elasticsearch/pom.xml
index f2a2efd..b9563c9 100644
--- a/mailbox/elasticsearch/pom.xml
+++ b/mailbox/elasticsearch/pom.xml
@@ -91,6 +91,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailbox/plugin/quota-mailing-cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-mailing-cassandra/pom.xml b/mailbox/plugin/quota-mailing-cassandra/pom.xml
index 849b385..8677f1f 100644
--- a/mailbox/plugin/quota-mailing-cassandra/pom.xml
+++ b/mailbox/plugin/quota-mailing-cassandra/pom.xml
@@ -91,6 +91,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>apache-mailet-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailbox/plugin/quota-mailing-memory/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-mailing-memory/pom.xml b/mailbox/plugin/quota-mailing-memory/pom.xml
index f28cd55..7ba4274 100644
--- a/mailbox/plugin/quota-mailing-memory/pom.xml
+++ b/mailbox/plugin/quota-mailing-memory/pom.xml
@@ -81,6 +81,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>apache-mailet-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailbox/plugin/quota-mailing/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-mailing/pom.xml b/mailbox/plugin/quota-mailing/pom.xml
index ec85841..6ad1c19 100644
--- a/mailbox/plugin/quota-mailing/pom.xml
+++ b/mailbox/plugin/quota-mailing/pom.xml
@@ -53,8 +53,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailbox/tika/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/tika/pom.xml b/mailbox/tika/pom.xml
index fc595d8..4564b56 100644
--- a/mailbox/tika/pom.xml
+++ b/mailbox/tika/pom.xml
@@ -38,8 +38,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>james-server-util-java8</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/base/pom.xml b/mailet/base/pom.xml
index a094b2e..6b1fd46 100644
--- a/mailet/base/pom.xml
+++ b/mailet/base/pom.xml
@@ -44,6 +44,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mailet-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>apache-mime4j-core</artifactId>
         </dependency>
         <dependency>
@@ -52,8 +57,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>javax-mail-extension</artifactId>
-            <type>test-jar</type>
+            <artifactId>james-server-util</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java b/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java
deleted file mode 100644
index 4efe093..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/****************************************************************
- * 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.mailet.base;
-
-import javax.mail.internet.AddressException;
-
-import org.apache.james.core.Domain;
-import org.apache.james.core.MailAddress;
-
-public class MailAddressFixture {
-    public static final String JAMES_LOCAL = "localhost";
-    public static final String JAMES_APACHE_ORG = "james.apache.org";
-    public static final String JAMES2_APACHE_ORG = "james2.apache.org";
-
-    public static final Domain JAMES_LOCAL_DOMAIN = Domain.of(JAMES_LOCAL);
-    public static final Domain JAMES_APACHE_ORG_DOMAIN = Domain.of(JAMES_APACHE_ORG);
-    public static final Domain JAMES2_APACHE_ORG_DOMAIN = Domain.of(JAMES2_APACHE_ORG);
-
-    public static final MailAddress SENDER = createMailAddress("sender@" + JAMES_LOCAL);
-    public static final MailAddress RECIPIENT1 = createMailAddress("recipient1@" + JAMES_LOCAL);
-    public static final MailAddress RECIPIENT2 = createMailAddress("recipient2@" + JAMES_LOCAL);
-    public static final MailAddress RECIPIENT3 = createMailAddress("recipient3@" + JAMES_LOCAL);
-
-    public static final MailAddress ANY_AT_LOCAL = createMailAddress("any@" + JAMES_LOCAL);
-    public static final MailAddress OTHER_AT_LOCAL = createMailAddress("other@" + JAMES_LOCAL);
-    public static final MailAddress ANY_AT_JAMES = createMailAddress("any@" + JAMES_APACHE_ORG);
-    public static final MailAddress POSTMASTER_AT_JAMES = createMailAddress("postmaster@" + JAMES_APACHE_ORG);
-    public static final MailAddress OTHER_AT_JAMES = createMailAddress("other@" + JAMES_APACHE_ORG);
-    public static final MailAddress ANY_AT_JAMES2 = createMailAddress("any@" + JAMES2_APACHE_ORG);
-    public static final MailAddress OTHER_AT_JAMES2 = createMailAddress("other@" + JAMES2_APACHE_ORG);
-
-    private static MailAddress createMailAddress(String mailAddress) {
-        try {
-            return new MailAddress(mailAddress);
-        } catch (AddressException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
deleted file mode 100644
index 6791a1f..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-
-import org.apache.james.core.MailAddress;
-import org.apache.james.core.builder.MimeMessageBuilder;
-import org.apache.james.util.MimeMessageUtil;
-import org.apache.mailet.Mail;
-import org.apache.mailet.PerRecipientHeaders;
-import org.apache.mailet.PerRecipientHeaders.Header;
-
-import com.github.fge.lambdas.Throwing;
-import com.github.steveash.guavate.Guavate;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-public class FakeMail implements Mail, Serializable {
-
-    private static final String DEFAULT_REMOTE_HOST = "111.222.333.444";
-    public static final String DEFAULT_REMOTE_ADDRESS = "127.0.0.1";
-
-    public static FakeMail fromMessage(MimeMessageBuilder message) throws MessagingException {
-        return FakeMail.builder()
-            .mimeMessage(message)
-            .build();
-    }
-
-    public static FakeMail fromMime(String text, String javaEncodingCharset, String javamailDefaultEncodingCharset) throws MessagingException, UnsupportedEncodingException {
-        Properties javamailProperties = new Properties();
-        javamailProperties.setProperty("mail.mime.charset", javamailDefaultEncodingCharset);
-        return FakeMail.builder()
-                .mimeMessage(MimeMessageUtil.mimeMessageFromBytes((text.getBytes(javaEncodingCharset))))
-                .build();
-    }
-
-    public static FakeMail fromMail(Mail mail) throws MessagingException {
-        return new FakeMail(mail.getMessage(),
-            Lists.newArrayList(mail.getRecipients()),
-            mail.getName(),
-            mail.getSender(),
-            mail.getState(),
-            mail.getErrorMessage(),
-            mail.getLastUpdated(),
-            attributes(mail),
-            mail.getMessageSize(),
-            mail.getRemoteAddr(),
-            mail.getRemoteHost(),
-            mail.getPerRecipientSpecificHeaders());
-    }
-
-    public static FakeMail from(MimeMessage message) throws MessagingException {
-        return builder()
-                .mimeMessage(message)
-                .build();
-    }
-
-    public static FakeMail from(MimeMessageBuilder message) throws MessagingException {
-        return from(message.build());
-    }
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-
-        private Optional<String> fileName;
-        private Optional<MimeMessage> mimeMessage;
-        private List<MailAddress> recipients;
-        private Optional<String> name;
-        private Optional<MailAddress> sender;
-        private Optional<String> state;
-        private Optional<String> errorMessage;
-        private Optional<Date> lastUpdated;
-        private Map<String, Serializable> attributes;
-        private Optional<Long> size;
-        private Optional<String> remoteAddr;
-        private Optional<String> remoteHost;
-        private PerRecipientHeaders perRecipientHeaders;
-
-        private Builder() {
-            fileName = Optional.empty();
-            mimeMessage = Optional.empty();
-            recipients = Lists.newArrayList();
-            name = Optional.empty();
-            sender = Optional.empty();
-            state = Optional.empty();
-            errorMessage = Optional.empty();
-            lastUpdated = Optional.empty();
-            attributes = Maps.newHashMap();
-            size = Optional.empty();
-            remoteAddr = Optional.empty();
-            remoteHost = Optional.empty();
-            perRecipientHeaders = new PerRecipientHeaders();
-        }
-
-        public Builder size(long size) {
-            this.size = Optional.of(size);
-            return this;
-        }
-
-        public Builder fileName(String fileName) {
-            this.fileName = Optional.of(fileName);
-            return this;
-        }
-
-        public Builder mimeMessage(MimeMessage mimeMessage) {
-            this.mimeMessage = Optional.of(mimeMessage);
-            return this;
-        }
-
-        public Builder mimeMessage(MimeMessageBuilder mimeMessage) throws MessagingException {
-            this.mimeMessage = Optional.of(mimeMessage.build());
-            return this;
-        }
-
-        public Builder recipients() {
-            return this;
-        }
-
-        public Builder recipients(List<MailAddress> recipients) {
-            this.recipients.addAll(recipients);
-            return this;
-        }
-
-        public Builder recipients(MailAddress... recipients) {
-            return recipients(ImmutableList.copyOf(recipients));
-        }
-
-        public Builder recipients(String... recipients) {
-            return recipients(Arrays.stream(recipients)
-                .map(Throwing.function(MailAddress::new))
-                .collect(Guavate.toImmutableList()));
-        }
-
-        public Builder recipient(MailAddress recipient) {
-            return recipients(recipient);
-        }
-
-        public Builder recipient(String recipient) throws AddressException {
-            return recipients(recipient);
-        }
-
-        public Builder name(String name) {
-            this.name = Optional.of(name);
-            return this;
-        }
-
-        public Builder sender(MailAddress sender) {
-            this.sender = Optional.of(sender);
-            return this;
-        }
-
-        public Builder sender(String sender) throws AddressException {
-            return sender(new MailAddress(sender));
-        }
-
-        public Builder state(String state) {
-            this.state = Optional.of(state);
-            return this;
-        }
-
-        public Builder errorMessage(String errorMessage) {
-            this.errorMessage = Optional.of(errorMessage);
-            return this;
-        }
-
-        public Builder lastUpdated(Date lastUpdated) {
-            this.lastUpdated = Optional.of(lastUpdated);
-            return this;
-        }
-
-        public Builder attribute(String name, Serializable object) {
-            this.attributes.put(name, object);
-            return this;
-        }
-
-        public Builder attributes(Map<String, Serializable> attributes) {
-            this.attributes.putAll(attributes);
-            return this;
-        }
-
-        public Builder remoteAddr(String remoteAddr) {
-            this.remoteAddr = Optional.of(remoteAddr);
-            return this;
-        }
-
-        public Builder remoteHost(String remoteHost) {
-            this.remoteHost = Optional.of(remoteHost);
-            return this;
-        }
-
-        public Builder addHeaderForRecipient(Header header, MailAddress recipient) {
-            this.perRecipientHeaders.addHeaderForRecipient(header, recipient);
-            return this;
-        }
-
-        public FakeMail build() throws MessagingException {
-            return new FakeMail(getMimeMessage(), recipients, name.orElse(null), sender.orElse(null), state.orElse(null), errorMessage.orElse(null), lastUpdated.orElse(null),
-                attributes, size.orElse(0L), remoteAddr.orElse(DEFAULT_REMOTE_ADDRESS), remoteHost.orElse(DEFAULT_REMOTE_HOST), perRecipientHeaders);
-        }
-
-        private MimeMessage getMimeMessage() throws MessagingException {
-            Preconditions.checkState(!(fileName.isPresent() && mimeMessage.isPresent()), "You can not specify a MimeMessage object when you alredy set Content from a file");
-            if (fileName.isPresent()) {
-                return MimeMessageUtil.mimeMessageFromStream(ClassLoader.getSystemResourceAsStream(fileName.get()));
-            }
-            return mimeMessage.orElse(null);
-        }
-    }
-
-    public static FakeMail defaultFakeMail() throws MessagingException {
-        return FakeMail.builder().build();
-    }
-
-    private static Map<String, Serializable> attributes(Mail mail) {
-        ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.builder();
-        for (String attributeName: ImmutableList.copyOf(mail.getAttributeNames())) {
-            builder.put(attributeName, mail.getAttribute(attributeName));
-        }
-        return builder.build();
-    }
-
-    private transient MimeMessage msg;
-    private Collection<MailAddress> recipients;
-    private String name;
-    private MailAddress sender;
-    private String state;
-    private String errorMessage;
-    private Date lastUpdated;
-    private Map<String, Serializable> attributes;
-    private long size;
-    private String remoteAddr;
-    private String remoteHost;
-    private PerRecipientHeaders perRecipientHeaders;
-    
-    public FakeMail(MimeMessage msg, List<MailAddress> recipients, String name, MailAddress sender, String state, String errorMessage, Date lastUpdated,
-            Map<String, Serializable> attributes, long size, String remoteAddr, String remoteHost, PerRecipientHeaders perRecipientHeaders) {
-        this.msg = msg;
-        this.recipients = recipients;
-        this.name = name;
-        this.sender = sender;
-        this.state = state;
-        this.errorMessage = errorMessage;
-        this.lastUpdated = lastUpdated;
-        this.attributes = attributes;
-        this.size = size;
-        this.remoteAddr = remoteAddr;
-        this.perRecipientHeaders = perRecipientHeaders;
-        this.remoteHost = remoteHost;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public void setName(String newName) {
-        this.name = newName;
-    }
-
-    @Override
-    public MimeMessage getMessage() throws MessagingException {
-        return msg;
-    }
-
-    @Override
-    public Collection<MailAddress> getRecipients() {
-        return recipients;
-    }
-
-    @Override
-    public void setRecipients(Collection<MailAddress> recipients) {
-        this.recipients = recipients;
-    }
-
-    @Override
-    public MailAddress getSender() {
-        return sender;
-    }
-
-    @Override
-    public String getState() {
-        return state;
-    }
-
-    @Override
-    public String getRemoteHost() {
-        return remoteHost;
-    }
-
-    @Override
-    public String getRemoteAddr() {
-        return remoteAddr;
-    }
-
-    @Override
-    public String getErrorMessage() {
-        return errorMessage;
-    }
-
-    @Override
-    public void setErrorMessage(String msg) {
-        this.errorMessage = msg;
-    }
-
-    @Override
-    public void setMessage(MimeMessage message) {
-        this.msg = message;
-        try {
-            if (message != null && message.getSender() != null) {
-                this.sender = new MailAddress((InternetAddress) message.getSender());
-            }
-        } catch (MessagingException e) {
-            throw new RuntimeException("Exception caught", e);
-        }
-    }
-
-    @Override
-    public void setState(String state) {
-        this.state = state;
-    }
-
-    @Override
-    public Serializable getAttribute(String name) {
-        return attributes.get(name);
-    }
-
-    @Override
-    public Iterator<String> getAttributeNames() {
-        return attributes.keySet().iterator();
-    }
-
-    @Override
-    public boolean hasAttributes() {
-        return !attributes.isEmpty();
-    }
-
-    @Override
-    public Serializable removeAttribute(String name) {
-        return attributes.remove(name);
-
-    }
-
-    @Override
-    public void removeAllAttributes() {
-        attributes.clear();
-    }
-
-    @Override
-    public Serializable setAttribute(String name, Serializable object) {
-        return attributes.put(name, object);
-    }
-
-    @Override
-    public long getMessageSize() throws MessagingException {
-        return size;
-    }
-
-    @Override
-    public Date getLastUpdated() {
-        return lastUpdated;
-    }
-
-    @Override
-    public void setLastUpdated(Date lastUpdated) {
-        this.lastUpdated = lastUpdated;
-    }
-
-    public void setMessageSize(long size) {
-        this.size = size;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof FakeMail) {
-            FakeMail that = (FakeMail) o;
-
-            return Objects.equal(this.size, that.size)
-                && Objects.equal(this.recipients, that.recipients)
-                && Objects.equal(this.name, that.name)
-                && Objects.equal(this.sender, that.sender)
-                && Objects.equal(this.state, that.state)
-                && Objects.equal(this.errorMessage, that.errorMessage)
-                && Objects.equal(this.lastUpdated, that.lastUpdated)
-                && Objects.equal(this.attributes, that.attributes)
-                && Objects.equal(this.remoteHost, that.remoteHost)
-                && Objects.equal(this.perRecipientHeaders, that.perRecipientHeaders)
-                && Objects.equal(this.remoteAddr, that.remoteAddr);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hashCode(name, sender, recipients, state, errorMessage, lastUpdated, attributes, size, remoteAddr, remoteHost, perRecipientHeaders);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("msg", msg)
-            .add("recipients", recipients)
-            .add("name", name)
-            .add("sender", sender)
-            .add("state", state)
-            .add("errorMessage", errorMessage)
-            .add("lastUpdated", lastUpdated)
-            .add("attributes", attributes)
-            .add("size", size)
-            .add("remoteAddr", remoteAddr)
-            .toString();
-    }
-
-    @Override
-    public PerRecipientHeaders getPerRecipientSpecificHeaders() {
-        return perRecipientHeaders;
-    }
-
-    @Override
-    public void addSpecificHeaderForRecipient(Header header, MailAddress recipient) {
-        perRecipientHeaders.addHeaderForRecipient(header, recipient);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
deleted file mode 100644
index eff41c9..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
+++ /dev/null
@@ -1,608 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.TimeUnit;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.MimeMessage;
-
-import org.apache.james.core.Domain;
-import org.apache.james.core.MailAddress;
-import org.apache.james.core.builder.MimeMessageWrapper;
-import org.apache.mailet.HostAddress;
-import org.apache.mailet.LookupException;
-import org.apache.mailet.Mail;
-import org.apache.mailet.MailetContext;
-import org.slf4j.Logger;
-
-import com.github.fge.lambdas.Throwing;
-import com.github.fge.lambdas.functions.ThrowingFunction;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-@SuppressWarnings("deprecation")
-public class FakeMailContext implements MailetContext {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static SentMail.Builder sentMailBuilder() {
-        return new SentMail.Builder();
-    }
-
-    public static SentMail.Builder fromMail(Mail mail) throws MessagingException {
-        return sentMailBuilder()
-            .sender(mail.getSender())
-            .recipients(mail.getRecipients())
-            .message(mail.getMessage())
-            .state(mail.getState())
-            .attributes(buildAttributesMap(mail))
-            .fromMailet();
-    }
-
-    private static ImmutableMap<String, Serializable> buildAttributesMap(Mail mail) {
-        Map<String, Serializable> result = new HashMap<>();
-        List<String> attributesNames = Lists.newArrayList(mail.getAttributeNames());
-        for (String attributeName: attributesNames) {
-            result.put(attributeName, mail.getAttribute(attributeName));
-        }
-        return ImmutableMap.copyOf(result);
-    }
-
-    public static FakeMailContext defaultContext() {
-        return builder().build();
-    }
-
-    public static class Builder {
-
-        private Logger logger;
-        private Optional<MailAddress> postmaster;
-
-        private Builder() {
-            postmaster = Optional.empty();
-        }
-
-        public Builder logger(Logger logger) {
-            this.logger = logger;
-            return this;
-        }
-
-        public Builder postmaster(MailAddress postmaster) {
-            this.postmaster = Optional.of(postmaster);
-            return this;
-        }
-
-        public FakeMailContext build() {
-            return new FakeMailContext(Optional.ofNullable(logger), postmaster.orElse(null));
-        }
-    }
-
-    public static class SentMail {
-
-        private static MimeMessage tryCopyMimeMessage(MimeMessage msg) throws MessagingException {
-            ThrowingFunction<MimeMessage, MimeMessage> throwingFunction = MimeMessageWrapper::wrap;
-
-            return Optional.ofNullable(msg)
-                .map(Throwing.function(throwingFunction).sneakyThrow())
-                .orElse(null);
-        }
-
-        public static class Builder {
-            private MailAddress sender;
-            private Optional<Collection<MailAddress>> recipients = Optional.empty();
-            private MimeMessage msg;
-            private Map<String, Serializable> attributes = new HashMap<>();
-            private Optional<String> state = Optional.empty();
-            private Optional<Boolean> fromMailet = Optional.empty();
-            private Optional<Delay> delay = Optional.empty();
-
-            public Builder sender(MailAddress sender) {
-                this.sender = sender;
-                return this;
-            }
-
-            public Builder sender(String sender) throws AddressException {
-                return sender(new MailAddress(sender));
-            }
-
-            public Builder recipients(Collection<MailAddress> recipients) {
-                this.recipients = Optional.of(recipients);
-                return this;
-            }
-
-            public Builder fromMailet() {
-                this.fromMailet = Optional.of(true);
-                return this;
-            }
-
-            public Builder recipients(MailAddress... recipients) {
-                this.recipients = Optional.<Collection<MailAddress>>of(ImmutableList.copyOf(recipients));
-                return this;
-            }
-
-            public Builder recipient(MailAddress recipient) {
-                Preconditions.checkNotNull(recipient);
-                return recipients(ImmutableList.of(recipient));
-            }
-
-            public Builder recipient(String recipient) throws AddressException {
-                Preconditions.checkNotNull(recipient);
-                return recipients(new MailAddress(recipient));
-            }
-
-            public Builder message(MimeMessage mimeMessage) {
-                this.msg = mimeMessage;
-                return this;
-            }
-
-            public Builder attributes(Map<String, Serializable> attributes) {
-                this.attributes.putAll(attributes);
-                return this;
-            }
-
-            public Builder attribute(String key, Serializable value) {
-                this.attributes.put(key, value);
-                return this;
-            }
-
-            public Builder state(String state) {
-                this.state = Optional.of(state);
-                return this;
-            }
-
-            public Builder delay(Delay delay) {
-                this.delay = Optional.of(delay);
-                return this;
-            }
-
-            public SentMail build() throws MessagingException {
-                if (fromMailet.orElse(false)) {
-                    this.attribute(Mail.SENT_BY_MAILET, "true");
-                }
-                return new SentMail(sender, recipients.orElse(ImmutableList.<MailAddress>of()), msg,
-                    ImmutableMap.copyOf(attributes), state.orElse(Mail.DEFAULT), delay);
-            }
-        }
-
-        private final MailAddress sender;
-        private final Collection<MailAddress> recipients;
-        private final MimeMessage msg;
-        private final Optional<String> subject;
-        private final Map<String, Serializable> attributes;
-        private final String state;
-        private final Optional<Delay> delay;
-
-        private SentMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, Map<String, Serializable> attributes, String state, Optional<Delay> delay) throws MessagingException {
-            this.sender = sender;
-            this.recipients = ImmutableList.copyOf(recipients);
-            this.msg = tryCopyMimeMessage(msg);
-            this.subject = getSubject(msg);
-            this.attributes = ImmutableMap.copyOf(attributes);
-            this.state = state;
-            this.delay = delay;
-        }
-
-        private Optional<String> getSubject(MimeMessage msg) {
-            try {
-                return Optional.ofNullable(msg.getSubject());
-            } catch (Exception e) {
-                return Optional.empty();
-            }
-        }
-
-        public MailAddress getSender() {
-            return sender;
-        }
-
-        public Collection<MailAddress> getRecipients() {
-            return recipients;
-        }
-
-        public MimeMessage getMsg() {
-            return msg;
-        }
-
-        public String getState() {
-            return state;
-        }
-
-        public Optional<String> getSubject() {
-            return subject;
-        }
-
-
-        public Optional<Delay> getDelay() {
-            return delay;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof SentMail)) {
-                return false;
-            }
-
-            SentMail sentMail = (SentMail) o;
-
-            return Objects.equals(this.sender, sentMail.sender)
-                && Objects.equals(this.recipients, sentMail.recipients)
-                && Objects.equals(this.attributes, sentMail.attributes)
-                && Objects.equals(this.state, sentMail.state);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(sender, recipients, attributes, state);
-        }
-
-        @Override
-        public String toString() {
-            return MoreObjects.toStringHelper(this)
-                .add("recipients", recipients)
-                .add("sender", sender)
-                .add("attributeNames", attributes)
-                .add("state", state)
-                .toString();
-        }
-    }
-
-    public static class Delay {
-        private final long duration;
-        private final TimeUnit timeUnit;
-
-        public Delay(long duration, TimeUnit timeUnit) {
-            this.duration = duration;
-            this.timeUnit = timeUnit;
-        }
-
-        public long getDuration() {
-            return duration;
-        }
-
-        public TimeUnit getTimeUnit() {
-            return timeUnit;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof Delay) {
-                Delay delay = (Delay) o;
-
-                return Objects.equals(this.duration, delay.duration)
-                    && Objects.equals(this.timeUnit, delay.timeUnit);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(duration, timeUnit);
-        }
-    }
-
-    public static class BouncedMail {
-        private final SentMail sentMail;
-        private final String message;
-        private final Optional<MailAddress> bouncer;
-
-        public BouncedMail(SentMail sentMail, String message, Optional<MailAddress> bouncer) {
-            this.sentMail = sentMail;
-            this.message = message;
-            this.bouncer = bouncer;
-        }
-
-        public BouncedMail(SentMail.Builder sentMail, String message, Optional<MailAddress> bouncer) throws MessagingException {
-            this(sentMail.build(), message, bouncer);
-        }
-
-        public SentMail getSentMail() {
-            return sentMail;
-        }
-
-        public String getMessage() {
-            return message;
-        }
-
-        public Optional<MailAddress> getBouncer() {
-            return bouncer;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o instanceof BouncedMail) {
-                BouncedMail that = (BouncedMail) o;
-                return Objects.equals(this.sentMail, that.sentMail)
-                    && Objects.equals(this.message, that.message)
-                    && Objects.equals(this.bouncer, that.bouncer);
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(sentMail, message, bouncer);
-        }
-
-        @Override
-        public String toString() {
-            return MoreObjects.toStringHelper(this)
-                .add("sentMail", sentMail)
-                .add("message", message)
-                .add("bouncer", bouncer)
-                .toString();
-        }
-    }
-
-    private final HashMap<String, Object> attributes;
-    private final Collection<SentMail> sentMails;
-    private final Collection<BouncedMail> bouncedMails;
-    private final Optional<Logger> logger;
-    private final MailAddress postmaster;
-
-    private FakeMailContext(Optional<Logger> logger, MailAddress postmaster) {
-        attributes = new HashMap<>();
-        sentMails = new ConcurrentLinkedQueue<>();
-        bouncedMails = new ConcurrentLinkedQueue<>();
-        this.logger = logger;
-        this.postmaster = postmaster;
-    }
-
-    @Override
-    public void bounce(Mail mail, String message) throws MessagingException {
-        bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.empty()));
-    }
-
-    @Override
-    public void bounce(Mail mail, String message, MailAddress bouncer) throws MessagingException {
-        bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.ofNullable(bouncer)));
-    }
-
-    /**
-     * @deprecated use the generic dnsLookup method
-     */
-    @Override
-    public Collection<String> getMailServers(Domain host) {
-        return null;  // trivial implementation
-    }
-
-    @Override
-    public MailAddress getPostmaster() {
-        return postmaster;
-    }
-
-    @Override
-    public Object getAttribute(String name) {
-        return attributes.get(name);
-    }
-
-    @Override
-    public Iterator<String> getAttributeNames() {
-        return attributes.keySet().iterator();
-    }
-
-    @Override
-    public int getMajorVersion() {
-        return 0;  // trivial implementation
-    }
-
-    @Override
-    public int getMinorVersion() {
-        return 0;  // trivial implementation
-    }
-
-    @Override
-    public String getServerInfo() {
-        return "Mock Server";
-    }
-
-    @Override
-    public boolean isLocalServer(Domain domain) {
-        return domain.equals(Domain.LOCALHOST);
-    }
-
-    /**
-     * @deprecated use {@link #isLocalEmail(MailAddress)} instead 
-     */
-    @Override
-    public boolean isLocalUser(String userAccount) {
-        return false;  // trivial implementation
-    }
-
-    @Override
-    public boolean isLocalEmail(MailAddress mailAddress) {
-        return false;  // trivial implementation
-    }
-
-    /**
-     * @deprecated use {@link #log(LogLevel level, String message)}
-     */
-    @Override
-    public void log(String message) {
-        System.out.println(message);
-    }
-
-    /**
-     * @deprecated use {@link #log(LogLevel level, String message, Throwable t)}
-     */
-    @Override
-    public void log(String message, Throwable t) {
-        System.out.println(message);
-        t.printStackTrace(System.out);
-    }
-
-    @Override
-    public void removeAttribute(String name) {
-        // trivial implementation
-    }
-
-    @Override
-    public void sendMail(MimeMessage mimemessage) throws MessagingException {
-        sentMails.add(sentMailBuilder()
-            .message(mimemessage)
-            .fromMailet()
-            .build());
-    }
-
-    @Override
-    public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg) throws MessagingException {
-        sentMails.add(sentMailBuilder()
-            .recipients(recipients)
-            .sender(sender)
-            .message(msg)
-            .fromMailet()
-            .build());
-    }
-
-    @Override
-    public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, String state) throws MessagingException {
-        sentMails.add(sentMailBuilder()
-            .recipients(recipients)
-            .message(msg)
-            .state(state)
-            .sender(sender)
-            .fromMailet()
-            .build());
-    }
-
-    @Override
-    public void sendMail(Mail mail) throws MessagingException {
-        sendMail(mail, Mail.DEFAULT);
-    }
-
-    @Override
-    public void sendMail(Mail mail, long delay, TimeUnit unit) throws MessagingException {
-        sendMail(mail, Mail.DEFAULT, delay, unit);
-    }
-
-    @Override
-    public void sendMail(Mail mail, String state) throws MessagingException {
-        mail.setState(state);
-        sentMails.add(fromMail(mail).build());
-    }
-
-    @Override
-    public void sendMail(Mail mail, String state, long delay, TimeUnit unit) throws MessagingException {
-        mail.setState(state);
-        sentMails.add(
-            fromMail(mail)
-                .delay(new Delay(delay, unit))
-                .build());
-    }
-
-    public void setAttribute(String name, Serializable object) {
-        attributes.put(name,object);
-    }
-
-    public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg) throws MessagingException {
-        // trivial implementation
-    }
-
-    /**
-     * @deprecated use the generic dnsLookup method
-     */
-    @Override
-    public Iterator<HostAddress> getSMTPHostAddresses(Domain domainName) {
-        return null;  // trivial implementation
-    }
-
-    @Override
-    public void setAttribute(String name, Object value) {
-        throw new UnsupportedOperationException("MOCKed method");
-    }
-
-    @Override
-    public void log(LogLevel level, String message) {
-        if (logger.isPresent()) {
-            switch (level) {
-            case INFO:
-                logger.get().info(message);
-                break;
-            case WARN:
-                logger.get().warn(message);
-                break;
-            case ERROR:
-                logger.get().error(message);
-                break;
-            default:
-                logger.get().debug(message);
-            }
-        } else {
-            System.out.println("[" + level + "]" + message);
-        }
-    }
-
-    @Override
-    public void log(LogLevel level, String message, Throwable t) {
-        if (logger.isPresent()) {
-            switch (level) {
-            case INFO:
-                logger.get().info(message, t);
-                break;
-            case WARN:
-                logger.get().warn(message, t);
-                break;
-            case ERROR:
-                logger.get().error(message, t);
-                break;
-            default:
-                logger.get().debug(message, t);
-            }
-        } else {
-            System.out.println("[" + level + "]" + message);
-            t.printStackTrace(System.out);
-        }
-    }
-
-    @Override
-    public List<String> dnsLookup(String name, RecordType type) throws LookupException {
-        return null;   // trivial implementation
-    }
-
-    public List<SentMail> getSentMails() {
-        return ImmutableList.copyOf(sentMails);
-    }
-
-    public void resetSentMails() {
-        sentMails.clear();
-    }
-
-    public List<BouncedMail> getBouncedMails() {
-        return ImmutableList.copyOf(bouncedMails);
-    }
-
-    @Override
-    public Logger getLogger() {
-        return logger.orElse(null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
deleted file mode 100644
index fc0c03c..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import static org.mockito.Mockito.mock;
-
-import javax.mail.internet.MimeMessage;
-
-import org.junit.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-import nl.jqno.equalsverifier.Warning;
-
-public class FakeMailTest {
-
-    @Test
-    public void beanShouldRespectBeanContract() {
-        EqualsVerifier.forClass(FakeMail.class)
-            .suppress(Warning.NONFINAL_FIELDS)
-            .withPrefabValues(MimeMessage.class, mock(MimeMessage.class), mock(MimeMessage.class))
-            .verify();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailetConfig.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailetConfig.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailetConfig.java
deleted file mode 100644
index 73289d7..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailetConfig.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import java.util.Iterator;
-import java.util.Optional;
-import java.util.Properties;
-
-import org.apache.mailet.MailetConfig;
-import org.apache.mailet.MailetContext;
-
-/**
- * MailetConfig over Properties
- */
-public class FakeMailetConfig implements MailetConfig {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-
-        private static final String DEFAULT_MAILET_NAME = "A Mailet";
-        private Optional<String> mailetName;
-        private Optional<MailetContext> mailetContext;
-        private Properties properties;
-
-        private Builder() {
-            mailetName = Optional.empty();
-            mailetContext = Optional.empty();
-            properties = new Properties();
-        }
-
-        public Builder mailetName(String mailetName) {
-            this.mailetName = Optional.ofNullable(mailetName);
-            return this;
-        }
-
-        public Builder mailetContext(MailetContext mailetContext) {
-            this.mailetContext = Optional.ofNullable(mailetContext);
-            return this;
-        }
-
-        public Builder mailetContext(FakeMailContext.Builder mailetContext) {
-            return mailetContext(mailetContext.build());
-        }
-
-        public Builder setProperty(String key, String value) {
-            this.properties.setProperty(key, value);
-            return this;
-        }
-
-        public FakeMailetConfig build() {
-            return new FakeMailetConfig(mailetName.orElse(DEFAULT_MAILET_NAME),
-                    mailetContext.orElse(FakeMailContext.defaultContext()),
-                    properties);
-        }
-    }
-
-    private final String mailetName;
-    private final MailetContext mailetContext;
-    private final Properties properties;
-
-    private FakeMailetConfig(String mailetName, MailetContext mailetContext, Properties properties) {
-        this.mailetName = mailetName;
-        this.mailetContext = mailetContext;
-        this.properties = properties;
-    }
-
-    @Override
-    public String getInitParameter(String name) {
-        return properties.getProperty(name);
-    }
-
-    @Override
-    public Iterator<String> getInitParameterNames() {
-        return properties.stringPropertyNames().iterator();
-    }
-
-    @Override
-    public MailetContext getMailetContext() {
-        return mailetContext;
-    }
-
-    @Override
-    public String getMailetName() {
-        return mailetName;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMatcherConfig.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMatcherConfig.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMatcherConfig.java
deleted file mode 100644
index 1917c3d..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMatcherConfig.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import java.util.Optional;
-
-import org.apache.mailet.MailetContext;
-import org.apache.mailet.MatcherConfig;
-
-import com.google.common.base.Preconditions;
-
-/**
- * MatcherConfig
- */
-public class FakeMatcherConfig implements MatcherConfig {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-
-        private String matcherName;
-        private Optional<MailetContext> mailetContext;
-        private Optional<String> condition;
-
-        private Builder() {
-            condition = Optional.empty();
-            mailetContext = Optional.empty();
-        }
-
-        public Builder matcherName(String matcherName) {
-            this.matcherName = matcherName;
-            return this;
-        }
-
-        public Builder mailetContext(MailetContext mailetContext) {
-            Preconditions.checkNotNull(mailetContext);
-            this.mailetContext = Optional.of(mailetContext);
-            return this;
-        }
-
-        public Builder condition(String condition) {
-            this.condition = Optional.ofNullable(condition);
-            return this;
-        }
-
-        public FakeMatcherConfig build() {
-            Preconditions.checkNotNull(matcherName, "'matcherName' is mandatory");
-            return new FakeMatcherConfig(matcherName, mailetContext.orElse(FakeMailContext.defaultContext()), condition);
-        }
-    }
-
-    private final String matcherName;
-    private final MailetContext mailetContext;
-    private final Optional<String> condition;
-
-    private FakeMatcherConfig(String matcherName, MailetContext mailetContext, Optional<String> condition) {
-        this.matcherName = matcherName;
-        this.mailetContext = mailetContext;
-        this.condition = condition;
-    }
-
-    @Override
-    public String getMatcherName() {
-        return matcherName;
-    }
-
-    @Override
-    public MailetContext getMailetContext() {
-        return mailetContext;
-    }
-
-    @Override
-    public String getCondition() {
-        return condition.orElse(null);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java b/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java
deleted file mode 100644
index ecbee4f..0000000
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************
- * 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.mailet.base.test;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
-import org.apache.james.core.MailAddress;
-import org.apache.james.core.builder.MimeMessageBuilder;
-import org.apache.mailet.Mail;
-
-/**
- * some utilities for James unit testing
- */
-public class MailUtil {
-
-    public static final String SENDER = "test@james.apache.org";
-    public static final String RECIPIENT = "test2@james.apache.org";
-    private static int m_counter = 0;
-
-    public static String newId() {
-        m_counter++;
-        return "MockMailUtil-ID-" + m_counter;
-    }
-
-    public static FakeMail createMockMail2Recipients() throws MessagingException {
-        return FakeMail.builder()
-                .name(newId())
-                .recipients(new MailAddress("test@james.apache.org"), new MailAddress("test2@james.apache.org"))
-                .build();
-    }
-
-    public static FakeMail createMockMail2Recipients(MimeMessage message) throws MessagingException {
-        return FakeMail.builder()
-                .name(newId())
-                .mimeMessage(message)
-                .recipients(new MailAddress("test@james.apache.org"), new MailAddress("test2@james.apache.org"))
-                .build();
-    }
-
-    public static MimeMessage createMimeMessage() throws MessagingException {
-        return createMimeMessage(null, null);
-    }
-    
-    public static MimeMessage createMimeMessageWithSubject(String subject) throws MessagingException {
-        return createMimeMessage(null, null, subject);
-    }
-
-    public static MimeMessage createMimeMessage(String headerName, String headerValue) throws MessagingException {
-        return createMimeMessage(headerName, headerValue, "testmail");
-    }
-    
-    private static MimeMessage createMimeMessage(String headerName, String headerValue, String subject) throws MessagingException {
-        MimeMessageBuilder mimeMessageBuilder = MimeMessageBuilder.mimeMessageBuilder()
-            .addToRecipient(RECIPIENT)
-            .addFrom(SENDER)
-            .setSubject(subject);
-        if (headerName != null) {
-            mimeMessageBuilder.addHeader(headerName, headerValue);
-        }
-        return mimeMessageBuilder.build();
-    }
-    
-    public static String toString(Mail mail, String charset) throws IOException, MessagingException {
-        ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
-        mail.getMessage().writeTo(
-                rawMessage,
-                new String[] { "Bcc", "Content-Length", "Message-ID" });
-        return rawMessage.toString(charset);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/icalendar/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/icalendar/pom.xml b/mailet/icalendar/pom.xml
index b11e5cb..767e9fb 100644
--- a/mailet/icalendar/pom.xml
+++ b/mailet/icalendar/pom.xml
@@ -36,8 +36,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
+            <artifactId>apache-mailet-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/pom.xml b/mailet/pom.xml
index 37cc224..722fc87 100644
--- a/mailet/pom.xml
+++ b/mailet/pom.xml
@@ -52,6 +52,7 @@
         <module>icalendar</module>
         <module>mailetdocs-maven-plugin</module>
         <module>standard</module>
+        <module>test</module>
     </modules>
 
     <issueManagement>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/standard/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/standard/pom.xml b/mailet/standard/pom.xml
index cd49a33..d0dc22b 100644
--- a/mailet/standard/pom.xml
+++ b/mailet/standard/pom.xml
@@ -43,9 +43,7 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-mailet-base</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
+            <artifactId>apache-mailet-test</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
@@ -54,6 +52,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/test/pom.xml b/mailet/test/pom.xml
new file mode 100644
index 0000000..80f5e64
--- /dev/null
+++ b/mailet/test/pom.xml
@@ -0,0 +1,138 @@
+<?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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>apache-mailet</artifactId>
+        <version>3.2.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>apache-mailet-test</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache James :: Test helpers for Mailet</name>
+    <description>Apache James Mailet Test is a collection of utilities to help testing mailets.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mailet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mime4j-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>javax-mail-extension</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.steveash.guavate</groupId>
+            <artifactId>guavate</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.activation</groupId>
+            <artifactId>activation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>nl.jqno.equalsverifier</groupId>
+            <artifactId>equalsverifier</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-guava</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>org.apache.mailet.base.*</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>${james.groupId}</groupId>
+                <artifactId>maven-mailetdocs-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3dddd7c5/mailet/test/src/main/java/org/apache/mailet/base/MailAddressFixture.java
----------------------------------------------------------------------
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/MailAddressFixture.java b/mailet/test/src/main/java/org/apache/mailet/base/MailAddressFixture.java
new file mode 100644
index 0000000..4efe093
--- /dev/null
+++ b/mailet/test/src/main/java/org/apache/mailet/base/MailAddressFixture.java
@@ -0,0 +1,56 @@
+/****************************************************************
+ * 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.mailet.base;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.Domain;
+import org.apache.james.core.MailAddress;
+
+public class MailAddressFixture {
+    public static final String JAMES_LOCAL = "localhost";
+    public static final String JAMES_APACHE_ORG = "james.apache.org";
+    public static final String JAMES2_APACHE_ORG = "james2.apache.org";
+
+    public static final Domain JAMES_LOCAL_DOMAIN = Domain.of(JAMES_LOCAL);
+    public static final Domain JAMES_APACHE_ORG_DOMAIN = Domain.of(JAMES_APACHE_ORG);
+    public static final Domain JAMES2_APACHE_ORG_DOMAIN = Domain.of(JAMES2_APACHE_ORG);
+
+    public static final MailAddress SENDER = createMailAddress("sender@" + JAMES_LOCAL);
+    public static final MailAddress RECIPIENT1 = createMailAddress("recipient1@" + JAMES_LOCAL);
+    public static final MailAddress RECIPIENT2 = createMailAddress("recipient2@" + JAMES_LOCAL);
+    public static final MailAddress RECIPIENT3 = createMailAddress("recipient3@" + JAMES_LOCAL);
+
+    public static final MailAddress ANY_AT_LOCAL = createMailAddress("any@" + JAMES_LOCAL);
+    public static final MailAddress OTHER_AT_LOCAL = createMailAddress("other@" + JAMES_LOCAL);
+    public static final MailAddress ANY_AT_JAMES = createMailAddress("any@" + JAMES_APACHE_ORG);
+    public static final MailAddress POSTMASTER_AT_JAMES = createMailAddress("postmaster@" + JAMES_APACHE_ORG);
+    public static final MailAddress OTHER_AT_JAMES = createMailAddress("other@" + JAMES_APACHE_ORG);
+    public static final MailAddress ANY_AT_JAMES2 = createMailAddress("any@" + JAMES2_APACHE_ORG);
+    public static final MailAddress OTHER_AT_JAMES2 = createMailAddress("other@" + JAMES2_APACHE_ORG);
+
+    private static MailAddress createMailAddress(String mailAddress) {
+        try {
+            return new MailAddress(mailAddress);
+        } catch (AddressException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[08/14] james-project git commit: JAMES-2502 merge util and util-java8

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java b/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
new file mode 100644
index 0000000..9dcae7a
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
@@ -0,0 +1,191 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+
+public class FluentFutureStream<T> {
+
+    private final CompletableFuture<Stream<T>> completableFuture;
+
+    /**
+     * Constructs a FluentFutureStream from a future of Stream.
+     */
+    public static <T> FluentFutureStream<T> of(CompletableFuture<Stream<T>> completableFuture) {
+        return new FluentFutureStream<>(completableFuture);
+    }
+
+    /**
+     * Constructs a FluentFutureStream from a Stream of Future
+     */
+    public static <T> FluentFutureStream<T> of(Stream<CompletableFuture<T>> completableFutureStream) {
+        return new FluentFutureStream<>(CompletableFutureUtil.allOf(completableFutureStream));
+    }
+
+    /**
+     * Constructs a FluentFutureStream from a Stream of Future of Stream.
+     *
+     * Underlying streams are flatMapped.
+     */
+    public static <T> FluentFutureStream<T> ofNestedStreams(Stream<CompletableFuture<Stream<T>>> completableFuture) {
+        return of(completableFuture)
+            .flatMap(Function.identity());
+    }
+
+    /**
+     * Constructs a FluentFutureStream from a Stream of Future of Optionals.
+     *
+     * Underlying optionals are unboxed.
+     */
+    public static <T> FluentFutureStream<T> ofOptionals(Stream<CompletableFuture<Optional<T>>> completableFuture) {
+        return of(completableFuture)
+            .flatMapOptional(Function.identity());
+    }
+
+    /**
+     * Constructs a FluentFutureStream from the supplied futures.
+     */
+    @SafeVarargs
+    public static <T> FluentFutureStream<T> ofFutures(CompletableFuture<T>... completableFutures) {
+        return new FluentFutureStream<>(CompletableFutureUtil.allOfArray(completableFutures));
+    }
+
+    private FluentFutureStream(CompletableFuture<Stream<T>> completableFuture) {
+        this.completableFuture = completableFuture;
+    }
+
+    /**
+     * For all values of the underlying stream, an action will be performed.
+     */
+    public FluentFutureStream<T> performOnAll(Function<T, CompletableFuture<Void>> action) {
+        return FluentFutureStream.of(
+            CompletableFutureUtil.performOnAll(completableFuture(), action));
+    }
+
+    /**
+     * Apply a transformation to all values of the underlying stream.
+     */
+    public <U> FluentFutureStream<U> map(Function<T, U> function) {
+        return FluentFutureStream.of(
+            CompletableFutureUtil.map(completableFuture(), function));
+    }
+
+    /**
+     * Apply a transformation to all value of the underlying stream.
+     *
+     * As the supplied transformation produces streams, the results will be flatMapped.
+     */
+    public <U> FluentFutureStream<U> flatMap(Function<T, Stream<U>> function) {
+        return FluentFutureStream.of(completableFuture().thenApply(stream ->
+            stream.flatMap(function)));
+    }
+
+    /**
+     * Apply a transformation to all value of the underlying stream.
+     *
+     * As the supplied transformation produces optionals, the results will be unboxed.
+     */
+    public <U> FluentFutureStream<U> flatMapOptional(Function<T, Optional<U>> function) {
+        return map(function)
+            .flatMap(OptionalUtils::toStream);
+    }
+
+    /**
+     * Apply a transformation to all value of the underlying stream.
+     *
+     * As the supplied transformation produces futures, we need to compose the returned values.
+     */
+    public <U> FluentFutureStream<U> thenComposeOnAll(Function<T, CompletableFuture<U>> function) {
+        return FluentFutureStream.of(
+            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function));
+    }
+
+    /**
+     * Apply a transformation to all value of the underlying stream.
+     *
+     * As the supplied transformation produces futures of stream, we need to compose then flatMap the returned values.
+     */
+    public <U> FluentFutureStream<U> thenFlatCompose(Function<T, CompletableFuture<Stream<U>>> function) {
+        return FluentFutureStream.of(
+            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function))
+            .flatMap(Function.identity());
+    }
+
+    /**
+     * Apply a transformation to all value of the underlying stream.
+     *
+     * As the supplied transformation produces futures of optionals, we need to compose then unbox the returned values.
+     */
+    public <U> FluentFutureStream<U> thenFlatComposeOnOptional(Function<T, CompletableFuture<Optional<U>>> function) {
+        return FluentFutureStream.of(
+            CompletableFutureUtil.thenComposeOnAll(completableFuture(), function))
+            .flatMapOptional(Function.identity());
+    }
+
+    /**
+     * Filter the values of the underlying stream.
+     */
+    public FluentFutureStream<T> filter(Predicate<T> predicate) {
+        return FluentFutureStream.of(completableFuture
+            .thenApply(stream -> stream.filter(predicate)));
+    }
+
+    /**
+     * Reduces the underlying stream. Reduced value is supplied as a Future of optional, as no empty value is supplied.
+     */
+    public CompletableFuture<Optional<T>> reduce(BinaryOperator<T> combiner) {
+        return CompletableFutureUtil.reduce(combiner, completableFuture);
+    }
+
+    /**
+     * educes the underlying stream. Reduced value is supplied as a Future, as an empty value is specified.
+     */
+    public CompletableFuture<T> reduce(T emptyAccumulator, BinaryOperator<T> combiner) {
+        return CompletableFutureUtil.reduce(combiner, completableFuture, emptyAccumulator);
+    }
+
+    /**
+     * Returns a future of the underlying stream.
+     */
+    public CompletableFuture<Stream<T>> completableFuture() {
+        return this.completableFuture;
+    }
+
+    /**
+     * Returns the future of the underlying collected stream.
+     */
+    public <C> CompletableFuture<C> collect(Collector<T, ?, C> collector) {
+        return this.completableFuture
+            .thenApply(stream -> stream.collect(collector));
+    }
+
+    /**
+     * Join and returns the underlying stream.
+     */
+    public Stream<T> join() {
+        return completableFuture().join();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/GuavaUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/GuavaUtils.java b/server/container/util/src/main/java/org/apache/james/util/GuavaUtils.java
new file mode 100644
index 0000000..518ead1
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/GuavaUtils.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableListMultimap;
+
+public class GuavaUtils {
+    public static <K, V> ImmutableListMultimap<K, V> toMultimap(Map<K, List<V>> rights) {
+        return rights.entrySet()
+            .stream()
+            .flatMap(e -> e.getValue().stream().map(right -> Pair.of(e.getKey(), right)))
+            .collect(Guavate.toImmutableListMultimap(Pair::getKey, Pair::getValue));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/Host.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/Host.java b/server/container/util/src/main/java/org/apache/james/util/Host.java
new file mode 100644
index 0000000..cb6acce
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/Host.java
@@ -0,0 +1,137 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.List;
+import java.util.Optional;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+public class Host {
+
+    public static ImmutableList<Host> parseHosts(String hostsString) {
+        return parseHosts(hostsString, Optional.empty());
+    }
+
+    public static ImmutableList<Host> parseHosts(String hostsString, int defaultPort) {
+        return parseHosts(hostsString, Optional.of(defaultPort));
+    }
+
+    private static ImmutableList<Host> parseHosts(String hostsString, Optional<Integer> defaultPort) {
+        return Splitter.on(',')
+            .omitEmptyStrings()
+            .splitToList(hostsString)
+            .stream()
+            .map(string -> Host.parse(string, defaultPort))
+            .distinct()
+            .collect(Guavate.toImmutableList());
+    }
+
+    public static Host from(String hostname, int port) {
+        return new Host(hostname, port);
+    }
+
+    public static Host parseConfString(String ipAndPort, int defaultPort) {
+        return parse(ipAndPort, Optional.of(defaultPort));
+    }
+
+    public static Host parseConfString(String ipAndPort) {
+        return parse(ipAndPort, Optional.empty());
+    }
+
+    public static Host parse(String ipAndPort, Optional<Integer> defaultPort) {
+        Preconditions.checkNotNull(ipAndPort);
+        Preconditions.checkArgument(!ipAndPort.isEmpty());
+
+        List<String> parts = retrieveHostParts(ipAndPort);
+
+        String ip = parts.get(0);
+        int port = getPortFromConfPart(parts, defaultPort);
+
+        return new Host(ip, port);
+    }
+
+    private static List<String> retrieveHostParts(String ipAndPort) {
+        List<String> parts = Splitter.on(':')
+                .trimResults()
+                .splitToList(ipAndPort);
+
+        if (parts.size() < 1 || parts.size() > 2) {
+            throw new IllegalArgumentException(ipAndPort + " is not a valid cassandra node");
+        }
+        return parts;
+    }
+
+    private static int getPortFromConfPart(List<String> parts, Optional<Integer> defaultPort) {
+        if (parts.size() == 2) {
+            return Integer.valueOf(parts.get(1));
+        }
+        if (parts.size() == 1) {
+            return defaultPort.orElseThrow(() -> new IllegalArgumentException("Host do not have port part but no default port provided"));
+        }
+        throw new RuntimeException("A host should be either a hostname or a hostname and a port separated by a ':'");
+    }
+
+    private final String hostName;
+    private final int port;
+
+    @VisibleForTesting
+    Host(String hostName, int port) {
+        Preconditions.checkNotNull(hostName, "Hostname could not be null");
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(hostName), "Hostname could not be empty");
+        Port.assertValid(port);
+        this.hostName = hostName;
+        this.port = port;
+    }
+
+    public String getHostName() {
+        return hostName;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hashCode(hostName, port);
+    }
+
+    @Override
+    public final boolean equals(Object object) {
+        if (object instanceof Host) {
+            Host that = (Host) object;
+            return Objects.equal(this.hostName, that.hostName)
+                && Objects.equal(this.port, that.port);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return this.hostName + ":" + this.port;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/MDCBuilder.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/MDCBuilder.java b/server/container/util/src/main/java/org/apache/james/util/MDCBuilder.java
new file mode 100644
index 0000000..e6709c8
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/MDCBuilder.java
@@ -0,0 +1,147 @@
+/****************************************************************
+ * 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.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class MDCBuilder {
+
+    public interface VoidOperation {
+        void perform();
+    }
+
+    public static <T> T withMdc(MDCBuilder mdcBuilder, Supplier<T> answerSupplier) {
+        try (Closeable closeable = mdcBuilder.build()) {
+            try {
+                return answerSupplier.get();
+            } catch (RuntimeException e) {
+                LOGGER.error("Got error, logging its context", e);
+                throw e;
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void withMdc(MDCBuilder mdcBuilder, VoidOperation logOperation) {
+        withMdc(mdcBuilder, () -> {
+            logOperation.perform();
+            return null;
+        });
+    }
+
+    public static final String HOST = "host";
+    public static final String IP = "ip";
+    public static final String PROTOCOL = "protocol";
+    public static final String USER = "user";
+    public static final String ACTION = "action";
+    public static final String SESSION_ID = "sessionId";
+    public static final String CHARSET = "charset";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MDCBuilder.class);
+
+    public static class Closeables implements Closeable {
+        private final List<Closeable> closeables;
+
+        public Closeables(List<Closeable> closeables) {
+            Preconditions.checkNotNull(closeables);
+            this.closeables = ImmutableList.copyOf(closeables);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closeables.forEach(this::closeQuietly);
+        }
+
+        private void closeQuietly(Closeable closeable) {
+            try {
+                closeable.close();
+            } catch (IOException e) {
+                LOGGER.warn("Failed to close Closeable", e);
+            }
+        }
+    }
+
+    public static MDCBuilder create() {
+        return new MDCBuilder();
+    }
+
+    private final ImmutableMap.Builder<String, String> contextMap = ImmutableMap.builder();
+    private final ImmutableList.Builder<MDCBuilder> nestedBuilder = ImmutableList.builder();
+
+    private MDCBuilder() {}
+
+    public MDCBuilder addContext(MDCBuilder nested) {
+        this.nestedBuilder.add(nested);
+        return this;
+    }
+
+    public MDCBuilder addContext(String key, Object value) {
+        Preconditions.checkNotNull(key);
+        Optional.ofNullable(value)
+            .ifPresent(nonNullValue -> contextMap.put(key, nonNullValue.toString()));
+        return this;
+    }
+
+    @VisibleForTesting
+    Map<String, String> buildContextMap() {
+        return ImmutableMap.<String, String>builder()
+            .putAll(nestedBuilder.build()
+                .stream()
+                .map(MDCBuilder::buildContextMap)
+                .flatMap(map -> map.entrySet().stream())
+                .collect(Guavate.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)))
+            .putAll(contextMap.build())
+            .build();
+    }
+
+    public <T> T execute(Supplier<T> supplier) {
+        return MDCBuilder.withMdc(this, supplier);
+    }
+
+    public <T> Supplier<T> wrapArround(Supplier<T> supplier) {
+        return () -> execute(supplier);
+    }
+
+    public Closeable build() {
+        return new Closeables(
+            buildContextMap()
+                .entrySet()
+                .stream()
+                .map(entry -> MDC.putCloseable(entry.getKey(), entry.getValue()))
+                .collect(Guavate.toImmutableList()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/MDCStructuredLogger.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/MDCStructuredLogger.java b/server/container/util/src/main/java/org/apache/james/util/MDCStructuredLogger.java
new file mode 100644
index 0000000..cf970ea
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/MDCStructuredLogger.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.function.Consumer;
+
+import org.slf4j.Logger;
+
+public class MDCStructuredLogger implements StructuredLogger {
+
+    public static MDCStructuredLogger forLogger(Logger logger) {
+        return new MDCStructuredLogger(logger);
+    }
+
+    private final Logger logger;
+    private final MDCBuilder mdcBuilder;
+
+    public MDCStructuredLogger(Logger logger) {
+        this.logger = logger;
+        this.mdcBuilder = MDCBuilder.create();
+    }
+
+    @Override
+    public StructuredLogger addField(String name, Object value) {
+        mdcBuilder.addContext(name, value);
+        return this;
+    }
+
+    @Override
+    public void log(Consumer<Logger> logOperation) {
+        MDCBuilder.withMdc(mdcBuilder, () -> logOperation.accept(logger));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/MemoizedSupplier.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/MemoizedSupplier.java b/server/container/util/src/main/java/org/apache/james/util/MemoizedSupplier.java
new file mode 100644
index 0000000..d0b4e3b
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/MemoizedSupplier.java
@@ -0,0 +1,30 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.function.Supplier;
+
+import com.google.common.base.Suppliers;
+
+public class MemoizedSupplier {
+    public static <T> Supplier<T> of(Supplier<T> originalSupplier) {
+        return Suppliers.memoize(originalSupplier::get)::get;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/OptionalUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/OptionalUtils.java b/server/container/util/src/main/java/org/apache/james/util/OptionalUtils.java
new file mode 100644
index 0000000..4a3449c
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/OptionalUtils.java
@@ -0,0 +1,68 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public class OptionalUtils {
+
+    @FunctionalInterface
+    public interface Operation {
+        void perform();
+    }
+
+    public static <T> Optional<T> executeIfEmpty(Optional<T> optional, Operation operation) {
+        if (!optional.isPresent()) {
+            operation.perform();
+        }
+        return optional;
+    }
+
+    public static <T> Stream<T> toStream(Optional<T> optional) {
+        return optional.map(Stream::of)
+            .orElse(Stream.of());
+    }
+
+    @SafeVarargs
+    public static <T> Optional<T> or(Optional<T>... optionals) {
+        return orStream(Arrays.stream(optionals));
+    }
+
+    @SafeVarargs
+    public static <T> Optional<T> orSuppliers(Supplier<Optional<T>>... suppliers) {
+        return orStream(Arrays.stream(suppliers)
+            .map(Supplier::get));
+    }
+
+    private static <T> Optional<T> orStream(Stream<Optional<T>> stream) {
+        return stream
+            .filter(Optional::isPresent)
+            .findFirst()
+            .orElse(Optional.empty());
+    }
+
+    public static <T> boolean containsDifferent(Optional<T> requestValue, T storeValue) {
+        return requestValue
+            .filter(value -> !value.equals(storeValue))
+            .isPresent();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/Port.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/Port.java b/server/container/util/src/main/java/org/apache/james/util/Port.java
new file mode 100644
index 0000000..016c4b4
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/Port.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Random;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Range;
+
+public class Port {
+    public static final int MAX_PORT_VALUE = 65535;
+    public static final int PRIVILEGED_PORT_BOUND = 1024;
+    private static final Range<Integer> VALID_PORT_RANGE = Range.closed(1, MAX_PORT_VALUE);
+
+    public static int generateValidUnprivilegedPort() {
+        return new Random().nextInt(Port.MAX_PORT_VALUE - PRIVILEGED_PORT_BOUND) + PRIVILEGED_PORT_BOUND;
+    }
+
+    public static void assertValid(int port) {
+        Preconditions.checkArgument(isValid(port), "Port should be between 1 and 65535");
+    }
+
+    public static boolean isValid(int port) {
+        return VALID_PORT_RANGE.contains(port);
+    }
+
+    private final int value;
+
+    public Port(int value) {
+        validate(value);
+        this.value = value;
+    }
+
+    protected void validate(int port) {
+        assertValid(port);
+    }
+
+    public int getValue() {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/Runnables.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/Runnables.java b/server/container/util/src/main/java/org/apache/james/util/Runnables.java
new file mode 100644
index 0000000..c199f31
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/Runnables.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Supplier;
+
+public class Runnables {
+    public static void runParallel(Runnable... runnables) {
+        FluentFutureStream.of(
+            Arrays.stream(runnables)
+                .map(runnable -> CompletableFuture.supplyAsync(toVoidSupplier(runnable))))
+            .join();
+    }
+
+    private static Supplier<Void> toVoidSupplier(Runnable runnable) {
+        return () -> {
+            runnable.run();
+            return null;
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/StreamUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/StreamUtils.java b/server/container/util/src/main/java/org/apache/james/util/StreamUtils.java
new file mode 100644
index 0000000..e8a71bd
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/StreamUtils.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.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+public class StreamUtils {
+
+    public static <T> Stream<T> ofNullable(T[] array) {
+        return ofOptional(Optional.ofNullable(array));
+    }
+
+    public static <T> Stream<T> ofOptional(Optional<T[]> array) {
+        return array
+            .map(Arrays::stream)
+            .orElse(Stream.empty());
+    }
+
+    public static <T> Stream<T> flatten(Collection<Stream<T>> streams) {
+        return flatten(streams.stream());
+    }
+
+    public static <T> Stream<T> flatten(Stream<Stream<T>> streams) {
+        return streams.flatMap(Function.identity());
+    }
+
+    @SafeVarargs
+    public static <T> Stream<T> flatten(Stream<T>... streams) {
+        return flatten(Arrays.stream(streams));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/StructuredLogger.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/StructuredLogger.java b/server/container/util/src/main/java/org/apache/james/util/StructuredLogger.java
new file mode 100644
index 0000000..f6fcec4
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/StructuredLogger.java
@@ -0,0 +1,30 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.function.Consumer;
+
+import org.slf4j.Logger;
+
+public interface StructuredLogger {
+    StructuredLogger addField(String name, Object value);
+
+    void log(Consumer<Logger> logOperation);
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/ValuePatch.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/ValuePatch.java b/server/container/util/src/main/java/org/apache/james/util/ValuePatch.java
new file mode 100644
index 0000000..5c3d01a
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/ValuePatch.java
@@ -0,0 +1,125 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+import com.google.common.base.Preconditions;
+
+public class ValuePatch<T> {
+
+    private enum State {
+        KEEP,
+        REMOVE,
+        MODIFY
+    }
+
+    public static <T> ValuePatch<T> modifyTo(T value) {
+        Preconditions.checkNotNull(value);
+        return new ValuePatch<>(value, State.MODIFY);
+    }
+
+    public static <T> ValuePatch<T> ofNullable(T value) {
+        return ofOptional(Optional.ofNullable(value));
+    }
+
+    public static <T> ValuePatch<T> ofOptional(Optional<T> value) {
+        Preconditions.checkNotNull(value);
+        return value.map(ValuePatch::modifyTo)
+            .orElse(ValuePatch.remove());
+    }
+
+    public static <T> ValuePatch<T> remove() {
+        return new ValuePatch<>(null, State.REMOVE);
+    }
+
+    public static <T> ValuePatch<T> keep() {
+        return new ValuePatch<>(null, State.KEEP);
+    }
+
+    private final T value;
+    private final State state;
+
+    private ValuePatch(T value, State state) {
+        this.value = value;
+        this.state = state;
+    }
+
+    public boolean isRemoved() {
+        return state == State.REMOVE;
+    }
+
+    public boolean isModified() {
+        return state == State.MODIFY;
+    }
+
+    public boolean isKept() {
+        return state == State.KEEP;
+    }
+
+    public <S> Optional<S> mapNotKeptToOptional(Function<Optional<T>, S> updateTransformation) {
+        if (isKept()) {
+            return Optional.empty();
+        }
+        return Optional.of(updateTransformation.apply(Optional.ofNullable(value)));
+    }
+
+    public T get() {
+        if (isModified()) {
+            return value;
+        } else {
+            throw new NoSuchElementException();
+        }
+    }
+
+    public Optional<T> notKeptOrElse(Optional<T> replacement) {
+        if (isKept()) {
+            return replacement;
+        }
+        return Optional.ofNullable(value);
+    }
+
+    public Optional<T> toOptional() {
+        return Optional.ofNullable(value);
+    }
+
+    public T getOrElse(T replacement) {
+        return toOptional().orElse(replacement);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof ValuePatch) {
+            ValuePatch<?> that = (ValuePatch<?>) o;
+            return Objects.equals(this.value, that.value) &&
+                Objects.equals(this.state, that.state);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(value, state);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java b/server/container/util/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
new file mode 100644
index 0000000..47b776a
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/date/DefaultZonedDateTimeProvider.java
@@ -0,0 +1,31 @@
+/****************************************************************
+ * 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.util.date;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+public class DefaultZonedDateTimeProvider implements ZonedDateTimeProvider {
+
+    @Override
+    public ZonedDateTime get() {
+        return ZonedDateTime.now(ZoneOffset.UTC);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java b/server/container/util/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
new file mode 100644
index 0000000..0a0d633
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/date/ImapDateTimeFormatter.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * 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.util.date;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.SignStyle;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ImapDateTimeFormatter {
+
+    private static final int INITIAL_YEAR = 1970;
+
+    public static DateTimeFormatter rfc5322() {
+        return new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .parseLenient()
+                .optionalStart()
+                    .appendText(DAY_OF_WEEK, dayOfWeek())
+                    .appendLiteral(", ")
+                .optionalEnd()
+                .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
+                .appendLiteral(' ')
+                .appendText(MONTH_OF_YEAR, monthOfYear())
+                .appendLiteral(' ')
+                .appendValueReduced(YEAR, 2, 4, INITIAL_YEAR)
+                .appendLiteral(' ')
+                .appendValue(HOUR_OF_DAY, 2)
+                .appendLiteral(':')
+                .appendValue(MINUTE_OF_HOUR, 2)
+                .optionalStart()
+                    .appendLiteral(':')
+                    .appendValue(SECOND_OF_MINUTE, 2)
+                .optionalEnd()
+                .appendLiteral(' ')
+                .appendOffset("+HHMM", "GMT")
+                .toFormatter();
+    }
+
+    private static ImmutableMap<Long, String> monthOfYear() {
+        return ImmutableMap.<Long, String>builder()
+                .put(1L, "Jan")
+                .put(2L, "Feb")
+                .put(3L, "Mar")
+                .put(4L, "Apr")
+                .put(5L, "May")
+                .put(6L, "Jun")
+                .put(7L, "Jul")
+                .put(8L, "Aug")
+                .put(9L, "Sep")
+                .put(10L, "Oct")
+                .put(11L, "Nov")
+                .put(12L, "Dec")
+                .build();
+    }
+
+    private static ImmutableMap<Long, String> dayOfWeek() {
+        return ImmutableMap.<Long, String>builder()
+                .put(1L, "Mon")
+                .put(2L, "Tue")
+                .put(3L, "Wed")
+                .put(4L, "Thu")
+                .put(5L, "Fri")
+                .put(6L, "Sat")
+                .put(7L, "Sun")
+                .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java b/server/container/util/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.java
new file mode 100644
index 0000000..6f80e76
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/date/ZonedDateTimeProvider.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.util.date;
+
+import java.time.ZonedDateTime;
+
+import javax.inject.Provider;
+
+public interface ZonedDateTimeProvider extends Provider<ZonedDateTime> {
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java b/server/container/util/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
new file mode 100644
index 0000000..74bb660
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/mime/MessageContentExtractor.java
@@ -0,0 +1,233 @@
+/****************************************************************
+ * 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.util.mime;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import javax.mail.internet.MimeMessage;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.dom.Body;
+import org.apache.james.mime4j.dom.Entity;
+import org.apache.james.mime4j.dom.Multipart;
+import org.apache.james.mime4j.dom.TextBody;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.functions.ThrowingFunction;
+
+public class MessageContentExtractor {
+
+    public static final String CONTENT_ID = "Content-ID";
+    public static final String MULTIPART_ALTERNATIVE = "multipart/alternative";
+    public static final String TEXT_HTML = "text/html";
+    public static final String TEXT_PLAIN = "text/plain";
+
+    public MessageContent extract(org.apache.james.mime4j.dom.Message message) throws IOException {
+        Body body = message.getBody();
+        if (body instanceof TextBody) {
+            return parseTextBody(message, (TextBody)body);
+        }
+        if (body instanceof Multipart) {
+            return parseMultipart(message, (Multipart)body);
+        }
+        return MessageContent.empty();
+    }
+
+    private MessageContent parseTextBody(Entity entity, TextBody textBody) throws IOException {
+        Optional<String> bodyContent = asString(textBody);
+        if (TEXT_HTML.equals(entity.getMimeType())) {
+            return MessageContent.ofHtmlOnly(bodyContent);
+        }
+        return MessageContent.ofTextOnly(bodyContent);
+    }
+
+    private MessageContent parseMultipart(Entity entity, Multipart multipart) throws IOException {
+        MessageContent messageContent = parseMultipartContent(entity, multipart);
+        if (!messageContent.isEmpty()) {
+            return messageContent;
+        }
+        return parseFirstFoundMultipart(multipart);
+    }
+
+    private MessageContent parseMultipartContent(Entity entity, Multipart multipart) throws IOException {
+        switch (entity.getMimeType()) {
+        case MULTIPART_ALTERNATIVE:
+            return retrieveHtmlAndPlainTextContent(multipart);
+        default:
+            return retrieveFirstReadablePart(multipart);
+        }
+    }
+
+    private MessageContent parseFirstFoundMultipart(Multipart multipart) throws IOException {
+        ThrowingFunction<Entity, MessageContent> parseMultipart = firstPart -> parseMultipart(firstPart, (Multipart)firstPart.getBody());
+        return multipart.getBodyParts()
+            .stream()
+            .filter(part -> part.getBody() instanceof Multipart)
+            .findFirst()
+            .map(Throwing.function(parseMultipart).sneakyThrow())
+            .orElse(MessageContent.empty());
+    }
+
+    private Optional<String> asString(TextBody textBody) throws IOException {
+        return Optional.ofNullable(IOUtils.toString(textBody.getInputStream(), charset(Optional.ofNullable(textBody.getMimeCharset()))));
+    }
+
+    private Charset charset(Optional<String> charset) {
+        return charset
+                .map(Charset::forName)
+                .orElse(org.apache.james.mime4j.Charsets.DEFAULT_CHARSET);
+    }
+
+    private MessageContent retrieveHtmlAndPlainTextContent(Multipart multipart) throws IOException {
+        Optional<String> textBody = getFirstMatchingTextBody(multipart, TEXT_PLAIN);
+        Optional<String> htmlBody = getFirstMatchingTextBody(multipart, TEXT_HTML);
+        MessageContent directChildTextBodies = new MessageContent(textBody, htmlBody);
+        if (!directChildTextBodies.isComplete()) {
+            MessageContent fromInnerMultipart = parseFirstFoundMultipart(multipart);
+            return directChildTextBodies.merge(fromInnerMultipart);
+        }
+        return directChildTextBodies;
+    }
+
+    private MessageContent retrieveFirstReadablePart(Multipart multipart) throws IOException {
+        return retrieveFirstReadablePartMatching(multipart, this::isNotAttachment)
+            .orElseGet(() -> retrieveFirstReadablePartMatching(multipart, this::isInlinedWithoutCid)
+                .orElse(MessageContent.empty()));
+    }
+
+    private Optional<MessageContent> retrieveFirstReadablePartMatching(Multipart multipart, Predicate<Entity> predicate) {
+        return multipart.getBodyParts()
+            .stream()
+            .filter(predicate)
+            .flatMap(Throwing.function(this::extractContentIfReadable).sneakyThrow())
+            .findFirst();
+    }
+
+    private Stream<MessageContent> extractContentIfReadable(Entity entity) throws IOException {
+        if (TEXT_HTML.equals(entity.getMimeType()) && entity.getBody() instanceof TextBody) {
+            return Stream.of(
+                    MessageContent.ofHtmlOnly(asString((TextBody)entity.getBody())));
+        }
+        if (TEXT_PLAIN.equals(entity.getMimeType()) && entity.getBody() instanceof TextBody) {
+            return Stream.of(
+                    MessageContent.ofTextOnly(asString((TextBody)entity.getBody())));
+        }
+        if (entity.isMultipart() && entity.getBody() instanceof Multipart) {
+            MessageContent innerMultipartContent = parseMultipart(entity, (Multipart)entity.getBody());
+            if (!innerMultipartContent.isEmpty()) {
+                return Stream.of(innerMultipartContent);
+            }
+        }
+        return Stream.empty();
+    }
+
+    private Optional<String> getFirstMatchingTextBody(Multipart multipart, String mimeType) throws IOException {
+        Optional<String> firstMatchingTextBody = getFirstMatchingTextBody(multipart, mimeType, this::isNotAttachment);
+        if (firstMatchingTextBody.isPresent()) {
+            return firstMatchingTextBody;
+        }
+        Optional<String> fallBackInlinedBodyWithoutCid = getFirstMatchingTextBody(multipart, mimeType, this::isInlinedWithoutCid);
+        return fallBackInlinedBodyWithoutCid;
+    }
+
+    private Optional<String> getFirstMatchingTextBody(Multipart multipart, String mimeType, Predicate<Entity> condition) {
+        Function<TextBody, Optional<String>> textBodyOptionalFunction = Throwing
+            .function(this::asString).sneakyThrow();
+
+        return multipart.getBodyParts()
+            .stream()
+            .filter(part -> mimeType.equals(part.getMimeType()))
+            .filter(condition)
+            .map(Entity::getBody)
+            .filter(TextBody.class::isInstance)
+            .map(TextBody.class::cast)
+            .findFirst()
+            .flatMap(textBodyOptionalFunction);
+    }
+
+    private boolean isNotAttachment(Entity part) {
+        return part.getDispositionType() == null;
+    }
+
+    private boolean isInlinedWithoutCid(Entity part) {
+        return Objects.equals(part.getDispositionType(), MimeMessage.INLINE)
+            && part.getHeader().getField(CONTENT_ID) == null;
+    }
+
+    public static class MessageContent {
+        private final Optional<String> textBody;
+        private final Optional<String> htmlBody;
+
+        public MessageContent(Optional<String> textBody, Optional<String> htmlBody) {
+            this.textBody = textBody;
+            this.htmlBody = htmlBody;
+        }
+
+        public static MessageContent ofTextOnly(Optional<String> textBody) {
+            return new MessageContent(textBody, Optional.empty());
+        }
+
+        public static MessageContent ofHtmlOnly(Optional<String> htmlBody) {
+            return new MessageContent(Optional.empty(), htmlBody);
+        }
+
+        public static MessageContent empty() {
+            return new MessageContent(Optional.empty(), Optional.empty());
+        }
+        
+        public Optional<String> getTextBody() {
+            return textBody;
+        }
+
+        public Optional<String> getHtmlBody() {
+            return htmlBody;
+        }
+        
+        public boolean isEmpty() {
+            return equals(empty());
+        }
+
+        public boolean isComplete() {
+            return textBody.isPresent() && htmlBody.isPresent();
+        }
+
+        public MessageContent merge(MessageContent fromInnerMultipart) {
+            return new MessageContent(
+                    textBody.map(Optional::of).orElse(fromInnerMultipart.getTextBody()),
+                    htmlBody.map(Optional::of).orElse(fromInnerMultipart.getHtmlBody()));
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == null || !(other instanceof MessageContent)) {
+                return false;
+            }
+            MessageContent otherMessageContent = (MessageContent)other;
+            return Objects.equals(this.textBody, otherMessageContent.textBody)
+                    && Objects.equals(this.htmlBody, otherMessageContent.htmlBody);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/streams/Iterators.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/streams/Iterators.java b/server/container/util/src/main/java/org/apache/james/util/streams/Iterators.java
new file mode 100644
index 0000000..ba3a06b
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/streams/Iterators.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.util.streams;
+
+import java.util.Iterator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class Iterators {
+
+    public static <T> Stream<T> toStream(Iterator<T> iterator) {
+        Iterable<T> iterable = () -> iterator;
+        return StreamSupport.stream(iterable.spliterator(), false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/streams/JamesCollectors.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/streams/JamesCollectors.java b/server/container/util/src/main/java/org/apache/james/util/streams/JamesCollectors.java
new file mode 100644
index 0000000..e705063
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/streams/JamesCollectors.java
@@ -0,0 +1,80 @@
+/****************************************************************
+ * 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.util.streams;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+public class JamesCollectors {
+    public static <D> Collector<D, ?, Stream<Collection<D>>> chunker(int chunkSize) {
+        return new ChunkCollector<>(chunkSize);
+    }
+
+    public static class ChunkCollector<D> implements Collector<D, Multimap<Integer, D>, Stream<Collection<D>>> {
+        private final int chunkSize;
+        private final AtomicInteger counter;
+
+        private ChunkCollector(int chunkSize) {
+            Preconditions.checkArgument(chunkSize > 0, "ChunkSize should be strictly positive");
+            this.chunkSize = chunkSize;
+            this.counter = new AtomicInteger(-1);
+        }
+
+        @Override
+        public Supplier<Multimap<Integer, D>> supplier() {
+            return ArrayListMultimap::create;
+        }
+
+        @Override
+        public BiConsumer<Multimap<Integer, D>, D> accumulator() {
+            return (accumulator, value) -> accumulator.put(counter.incrementAndGet() / chunkSize, value);
+        }
+
+        @Override
+        public BinaryOperator<Multimap<Integer, D>> combiner() {
+            return (accumulator1, accumulator2) -> {
+                accumulator1.putAll(accumulator2);
+                return accumulator1;
+            };
+        }
+
+        @Override
+        public Function<Multimap<Integer, D>, Stream<Collection<D>>> finisher() {
+            return accumulator -> accumulator.asMap().values().stream();
+        }
+
+        @Override
+        public Set<Characteristics> characteristics() {
+            return ImmutableSet.of();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/streams/Limit.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/streams/Limit.java b/server/container/util/src/main/java/org/apache/james/util/streams/Limit.java
new file mode 100644
index 0000000..268ed5e
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/streams/Limit.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.util.streams;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import com.google.common.base.Preconditions;
+
+public class Limit {
+
+    public static Limit from(int limit) {
+        if (limit > 0) {
+            return new Limit(Optional.of(limit));
+        } else {
+            return unlimited();
+        }
+    }
+
+    public static Limit from(Optional<Integer> limit) {
+        return limit.map(Limit::from)
+            .orElse(unlimited());
+    }
+
+    public static Limit unlimited() {
+        return new Limit(Optional.empty());
+    }
+
+    public static Limit limit(int limit) {
+        Preconditions.checkArgument(limit > 0, "limit should be positive");
+        return new Limit(Optional.of(limit));
+    }
+
+    private final Optional<Integer> limit;
+
+    private Limit(Optional<Integer> limit) {
+        this.limit = limit;
+    }
+
+    public Optional<Integer> getLimit() {
+        return limit;
+    }
+
+    public <T> Stream<T> applyOnStream(Stream<T> stream) {
+        return limit
+            .map(stream::limit)
+            .orElse(stream);
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof Limit) {
+            Limit other = (Limit) o;
+            return Objects.equals(limit, other.limit);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(limit);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/main/java/org/apache/james/util/streams/Offset.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/streams/Offset.java b/server/container/util/src/main/java/org/apache/james/util/streams/Offset.java
new file mode 100644
index 0000000..109ecae
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/streams/Offset.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * 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.util.streams;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import com.google.common.base.Preconditions;
+
+public class Offset {
+
+    public static Offset from(Optional<Integer> offset) {
+        return offset.map(Offset::from)
+            .orElse(none());
+    }
+
+    public static Offset none() {
+        return new Offset(0);
+    }
+
+    public static Offset from(int offset) {
+        Preconditions.checkArgument(offset >= 0, "offset should be positive");
+        return new Offset(offset);
+    }
+
+    private final int offset;
+
+    private Offset(int offset) {
+        this.offset = offset;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof Offset) {
+            Offset other = (Offset) o;
+            return Objects.equals(this.offset, other.offset);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(offset);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/CommutativityChecker.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/CommutativityChecker.java b/server/container/util/src/test/java/org/apache/james/util/CommutativityChecker.java
new file mode 100644
index 0000000..15976e9
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/CommutativityChecker.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Set;
+import java.util.function.BinaryOperator;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.paukov.combinatorics3.Generator;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+
+public class CommutativityChecker<T> {
+    private final Set<T> valuesToTest;
+    private final BinaryOperator<T> operationToTest;
+
+    public CommutativityChecker(Set<T> valuesToTest, BinaryOperator<T> operationToTest) {
+        Preconditions.checkNotNull(valuesToTest);
+        Preconditions.checkNotNull(operationToTest);
+        Preconditions.checkArgument(valuesToTest.size() > 1, "You must to pass more than one value to check commutativity");
+        this.valuesToTest = valuesToTest;
+        this.operationToTest = operationToTest;
+    }
+
+    public Set<Pair<T, T>> findNonCommutativeInput() {
+        return Generator.combination(valuesToTest)
+            .simple(2)
+            .stream()
+            .map(list -> Pair.of(list.get(0), list.get(1)))
+            .filter(this::isNotCommutative)
+            .collect(Guavate.toImmutableSet());
+    }
+
+    private boolean isNotCommutative(Pair<T, T> pair) {
+        T leftThenRight = operationToTest.apply(pair.getLeft(), pair.getRight());
+        T rightThenLeft = operationToTest.apply(pair.getRight(), pair.getLeft());
+        return !leftThenRight.equals(rightThenLeft);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/630dcab1/server/container/util/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/CommutativityCheckerTest.java b/server/container/util/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
new file mode 100644
index 0000000..ec0802a
--- /dev/null
+++ b/server/container/util/src/test/java/org/apache/james/util/CommutativityCheckerTest.java
@@ -0,0 +1,102 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Set;
+import java.util.function.BinaryOperator;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class CommutativityCheckerTest {
+    @Test
+    public void constructorShouldThrowWhenNullValuesToTest() throws Exception {
+        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
+
+        assertThatThrownBy(() -> new CommutativityChecker<>(null, binaryOperator))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenEmptyValuesToTest() throws Exception {
+        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
+
+        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(), binaryOperator))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenSingleValueToTest() throws Exception {
+        BinaryOperator<Integer> binaryOperator = (a, b) -> a * a + b;
+
+        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(0), binaryOperator))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullOperation() throws Exception {
+        assertThatThrownBy(() -> new CommutativityChecker<>(ImmutableSet.of(0, 1), null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void findNonCommutativeInputShouldReturnEmptyWhenCommutativeOperation() throws Exception {
+        Set<Integer> integers = ImmutableSet.of(5, 4, 3, 2, 1);
+        BinaryOperator<Integer> commutativeOperator = (a, b) -> a + b;
+        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, commutativeOperator);
+
+        assertThat(commutativityChecker.findNonCommutativeInput()).isEmpty();
+    }
+
+    @Test
+    public void findNonCommutativeInputShouldReturnDataWhenNonCommutativeOperation() throws Exception {
+        Set<Integer> integers = ImmutableSet.of(2, 1);
+        BinaryOperator<Integer> nonCommutativeOperator = (a, b) -> 2 * a + b;
+        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, nonCommutativeOperator);
+
+        assertThat(commutativityChecker.findNonCommutativeInput())
+            .containsOnly(Pair.of(2, 1));
+    }
+
+    @Test
+    public void findNonCommutativeInputShouldNotReturnStableValues() throws Exception {
+        Set<Integer> integers = ImmutableSet.of(0, 1, 2);
+        BinaryOperator<Integer> nonCommutativeOperatorWithStableValues = (a, b) -> a * a + b;
+        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(integers, nonCommutativeOperatorWithStableValues);
+
+        assertThat(commutativityChecker.findNonCommutativeInput())
+            .containsOnly(Pair.of(1, 2),
+                Pair.of(0, 2));
+    }
+
+    @Test
+    public void findNonCommutativeInputShouldReturnEmptyWhenNonCommutativeOperationButOnlyStableValues() throws Exception {
+        Set<Integer> stableValues = ImmutableSet.of(0, 1);
+        BinaryOperator<Integer> nonCommutativeOperatorWithStableValues = (a, b) -> a * a + b;
+        CommutativityChecker<Integer> commutativityChecker = new CommutativityChecker<>(stableValues, nonCommutativeOperatorWithStableValues);
+
+        assertThat(commutativityChecker.findNonCommutativeInput()).isEmpty();
+    }
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org