You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/12/03 02:32:21 UTC

[james-project] 02/09: JAMES-2988 Back fetchGroup with an enumSet

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 2af458075c3537e5e9e70f4567e03b47f5cd7606
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Nov 28 11:58:20 2019 +0700

    JAMES-2988 Back fetchGroup with an enumSet
---
 mailbox/api/pom.xml                                |   5 +
 .../org/apache/james/mailbox/model/FetchGroup.java |  92 +++++++++++-------
 .../apache/james/mailbox/model/MessageResult.java  |  10 +-
 .../james/mailbox/model/PartContentDescriptor.java |  42 ++++----
 .../apache/james/mailbox/model/FetchGroupTest.java | 106 ++++++++-------------
 .../mailbox/model/PartContentDescriptorTest.java   |  22 -----
 .../apache/james/mailbox/store/ResultUtils.java    |  36 ++++---
 .../mailbox/store/mail/FetchGroupConverter.java    |  20 ++--
 .../james/mailbox/store/ResultUtilsTest.java       |  61 ++++++++++++
 .../store/mail/FetchGroupConverterTest.java        |  10 +-
 .../imap/processor/fetch/FetchDataConverter.java   |  21 ++--
 .../processor/fetch/FetchDataConverterTest.java    |  19 ++--
 12 files changed, 249 insertions(+), 195 deletions(-)

diff --git a/mailbox/api/pom.xml b/mailbox/api/pom.xml
index 8a882d7..616dc68 100644
--- a/mailbox/api/pom.xml
+++ b/mailbox/api/pom.xml
@@ -106,6 +106,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/FetchGroup.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/FetchGroup.java
index 7923774..05844e4 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/FetchGroup.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/FetchGroup.java
@@ -20,18 +20,42 @@
 package org.apache.james.mailbox.model;
 
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 
 /**
  * Indicates the results fetched.
  */
 public class FetchGroup {
+    public enum Profile {
+        MIME_DESCRIPTOR(MIME_DESCRIPTOR_MASK),
+        HEADERS(HEADERS_MASK),
+        FULL_CONTENT(FULL_CONTENT_MASK),
+        BODY_CONTENT(BODY_CONTENT_MASK),
+        MIME_HEADERS(MIME_HEADERS_MASK),
+        MIME_CONTENT(MIME_CONTENT_MASK);
+
+        public static EnumSet<Profile> of(int content) {
+            return Arrays.stream(values())
+                .filter(value -> (content & value.mask) > 0)
+                .collect(Collectors.toCollection(() -> EnumSet.noneOf(Profile.class)));
+        }
+
+        private final int mask;
+
+        Profile(int mask) {
+            this.mask = mask;
+        }
+    }
+
     /**
      * For example: could have best performance when doing store and then
      * forget. UIDs are always returned
@@ -45,43 +69,49 @@ public class FetchGroup {
     public static final int MIME_HEADERS_MASK = 0x800;
     public static final int MIME_CONTENT_MASK = 0x1000;
 
-    public static final FetchGroup MINIMAL = new FetchGroup(MINIMAL_MASK);
-    public static final FetchGroup HEADERS = new FetchGroup(HEADERS_MASK);
-    public static final FetchGroup FULL_CONTENT = new FetchGroup(FULL_CONTENT_MASK);
-    public static final FetchGroup BODY_CONTENT = new FetchGroup(BODY_CONTENT_MASK);
+    public static final FetchGroup MINIMAL = new FetchGroup(EnumSet.noneOf(Profile.class));
+    public static final FetchGroup HEADERS = new FetchGroup(EnumSet.of(Profile.HEADERS));
+    public static final FetchGroup FULL_CONTENT = new FetchGroup(EnumSet.of(Profile.FULL_CONTENT));
+    public static final FetchGroup BODY_CONTENT = new FetchGroup(EnumSet.of(Profile.BODY_CONTENT));
 
-    private final int content;
+    private final EnumSet<Profile> content;
     private final ImmutableSet<PartContentDescriptor> partContentDescriptors;
 
     @VisibleForTesting
-    FetchGroup(int content) {
+    FetchGroup(EnumSet<Profile> content) {
         this(content, ImmutableSet.of());
     }
 
     @VisibleForTesting
-    FetchGroup(int content, ImmutableSet<PartContentDescriptor> partContentDescriptors) {
+    FetchGroup(EnumSet<Profile> content, ImmutableSet<PartContentDescriptor> partContentDescriptors) {
         this.content = content;
         this.partContentDescriptors = partContentDescriptors;
     }
 
     /**
-     * Contents to be fetched. Composed bitwise.
+     * Profiles to be fetched.
      *
-     * @return masks to be used for bitewise operations.
-     * @see #MINIMAL_MASK
-     * @see #MIME_DESCRIPTOR_MASK
-     * @see #HEADERS_MASK
-     * @see #FULL_CONTENT_MASK
-     * @see #BODY_CONTENT_MASK
-     * @see #MIME_HEADERS_MASK
-     * @see #MIME_CONTENT_MASK
+     * @return Return an enumset of profiles to be fetched
+     * @see Profile
      */
-    public int content() {
+    public EnumSet<Profile> profiles() {
         return content;
     }
 
     public FetchGroup with(int content) {
-         return new FetchGroup(this.content | content, partContentDescriptors);
+        return with(Profile.of(content));
+    }
+
+    public FetchGroup with(Profile... profiles) {
+        Preconditions.checkArgument(profiles.length > 0);
+        return with(EnumSet.copyOf(ImmutableSet.copyOf(profiles)));
+    }
+
+    public FetchGroup with(EnumSet<Profile> profiles) {
+        EnumSet<Profile> result = EnumSet.noneOf(Profile.class);
+        result.addAll(this.content);
+        result.addAll(profiles);
+        return new FetchGroup(result, partContentDescriptors);
     }
 
     /**
@@ -96,15 +126,15 @@ public class FetchGroup {
     }
 
     /**
-     * Adds content for the particular part.
+     * Adds profiles for the particular part.
      * 
      * @param path
      *            <code>MimePath</code>, not null
-     * @param content
-     *            bitwise content constant
+     * @param profiles
+     *            bitwise profiles constant
      */
-    public FetchGroup addPartContent(MimePath path, int content) {
-        PartContentDescriptor newContent = retrieveUpdatedPartContentDescriptor(path, content);
+    public FetchGroup addPartContent(MimePath path, EnumSet<Profile> profiles) {
+        PartContentDescriptor newContent = retrieveUpdatedPartContentDescriptor(path, profiles);
 
         return new FetchGroup(this.content,
             Stream.concat(
@@ -114,23 +144,11 @@ public class FetchGroup {
                 .collect(Guavate.toImmutableSet()));
     }
 
-    private PartContentDescriptor retrieveUpdatedPartContentDescriptor(MimePath path, int content) {
+    private PartContentDescriptor retrieveUpdatedPartContentDescriptor(MimePath path, EnumSet<Profile> profiles) {
         return partContentDescriptors.stream()
                 .filter(descriptor -> path.equals(descriptor.path()))
                 .findFirst()
-                .orElse(new PartContentDescriptor(path))
-                .or(content);
-    }
-
-    public boolean hasMask(int mask) {
-        return (content & mask) > NO_MASK;
-    }
-
-    public boolean hasOnlyMasks(int... masks) {
-        int allowedMask = Arrays.stream(masks)
-            .reduce((a, b) -> a | b)
-            .orElse(0);
-        return (content & (~ allowedMask)) == 0;
+                .orElse(new PartContentDescriptor(profiles, path));
     }
 
     @Override
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageResult.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageResult.java
index 82894d6..b21f5ce 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageResult.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageResult.java
@@ -84,7 +84,7 @@ public interface MessageResult extends Comparable<MessageResult> {
      * @param path
      *            describing the part's position within a multipart message
      * @return <code>Header</code> <code>Iterator</code>, or null when
-     *         {@link FetchGroup#content()} does not include the index and
+     *         {@link FetchGroup#profiles()} does not include the index and
      *         when the mime part cannot be found
      */
     Iterator<Header> iterateHeaders(MimePath path) throws MailboxException;
@@ -95,7 +95,7 @@ public interface MessageResult extends Comparable<MessageResult> {
      * @param path
      *            describing the part's position within a multipart message
      * @return <code>Header</code> <code>Iterator</code>, or null when
-     *         {@link FetchGroup#content()} does not include the index and
+     *         {@link FetchGroup#profiles()} does not include the index and
      *         when the mime part cannot be found
      */
     Iterator<Header> iterateMimeHeaders(MimePath path) throws MailboxException;
@@ -116,7 +116,7 @@ public interface MessageResult extends Comparable<MessageResult> {
      * @param path
      *            describes the part
      * @return <code>Content</code>, or null when
-     *         {@link FetchGroup#content()} did not been include the given
+     *         {@link FetchGroup#profiles()} did not been include the given
      *         index and when the mime part cannot be found
      */
     Content getFullContent(MimePath path) throws MailboxException;
@@ -137,7 +137,7 @@ public interface MessageResult extends Comparable<MessageResult> {
      * @param path
      *            describes the part
      * @return <code>Content</code>, or null when
-     *         {@link FetchGroup#content()} did not been include the given
+     *         {@link FetchGroup#profiles()} did not been include the given
      *         index and when the mime part cannot be found
      */
     Content getBody(MimePath path) throws MailboxException;
@@ -148,7 +148,7 @@ public interface MessageResult extends Comparable<MessageResult> {
      * @param path
      *            describes the part
      * @return <code>Content</code>, or null when
-     *         {@link FetchGroup#content()} did not been include the given
+     *         {@link FetchGroup#profiles()} did not been include the given
      *         index and when the mime part cannot be found
      */
     Content getMimeBody(MimePath path) throws MailboxException;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/PartContentDescriptor.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/PartContentDescriptor.java
index 089d1fd..a0ce5bf 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/PartContentDescriptor.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/PartContentDescriptor.java
@@ -19,45 +19,49 @@
 
 package org.apache.james.mailbox.model;
 
-import static org.apache.james.mailbox.model.FetchGroup.NO_MASK;
-
+import java.util.EnumSet;
 import java.util.Objects;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
 /**
  * Describes the contents to be fetched for a mail part. All
  * implementations MUST implement equals. Two implementations are equal
  * if and only if their paths are equal.
  */
 public class PartContentDescriptor {
-    private final int content;
+    private final EnumSet<FetchGroup.Profile> content;
     private final MimePath path;
 
     public PartContentDescriptor(MimePath path) {
-        this(0, path);
+        this(EnumSet.noneOf(FetchGroup.Profile.class), path);
     }
 
-    public PartContentDescriptor(int content, MimePath path) {
+    public PartContentDescriptor(EnumSet<FetchGroup.Profile> content, MimePath path) {
         this.content = content;
         this.path = path;
     }
 
-    public PartContentDescriptor or(int content) {
-        return new PartContentDescriptor(this.content | content, path);
+    public PartContentDescriptor with(FetchGroup.Profile... profiles) {
+        Preconditions.checkArgument(profiles.length > 0);
+        return with(EnumSet.copyOf(ImmutableSet.copyOf(profiles)));
+    }
+
+    public PartContentDescriptor with(EnumSet<FetchGroup.Profile> profiles) {
+        EnumSet<FetchGroup.Profile> result = EnumSet.noneOf(FetchGroup.Profile.class);
+        result.addAll(this.content);
+        result.addAll(profiles);
+        return new PartContentDescriptor(result, path);
     }
 
     /**
-     * Contents to be fetched. Composed bitwise.
+     * Profiles to be fetched.
      *
-     * @return bitwise descripion
-     * @see FetchGroup#MINIMAL_MASK
-     * @see FetchGroup#MIME_DESCRIPTOR_MASK
-     * @see FetchGroup#HEADERS_MASK
-     * @see FetchGroup#FULL_CONTENT_MASK
-     * @see FetchGroup#BODY_CONTENT_MASK
-     * @see FetchGroup#MIME_HEADERS_MASK
-     * @see FetchGroup#MIME_CONTENT_MASK
+     * @return Return an enumset of profiles to be fetched
+     * @see FetchGroup.Profile
      */
-    public int content() {
+    public EnumSet<FetchGroup.Profile> profiles() {
         return content;
     }
 
@@ -70,10 +74,6 @@ public class PartContentDescriptor {
         return path;
     }
 
-    public boolean hasMask(int mask) {
-        return (content & mask) > NO_MASK;
-    }
-
     @Override
     public final int hashCode() {
         return Objects.hash(path);
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/FetchGroupTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/FetchGroupTest.java
index 1ad5baa..b0b072f 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/FetchGroupTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/FetchGroupTest.java
@@ -21,13 +21,38 @@ package org.apache.james.mailbox.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.EnumSet;
+import java.util.stream.Stream;
+
+import org.apache.james.mailbox.model.FetchGroup.Profile;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import com.google.common.collect.ImmutableSet;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
 class FetchGroupTest {
+    static Stream<Arguments> ofContentShouldReturnCorrectValue() {
+        return Stream.of(
+            Arguments.arguments(0, EnumSet.noneOf(Profile.class)),
+            Arguments.arguments(FetchGroup.MIME_DESCRIPTOR_MASK, EnumSet.of(Profile.MIME_DESCRIPTOR)),
+            Arguments.arguments(FetchGroup.BODY_CONTENT_MASK, EnumSet.of(Profile.BODY_CONTENT)),
+            Arguments.arguments(FetchGroup.FULL_CONTENT_MASK, EnumSet.of(Profile.FULL_CONTENT)),
+            Arguments.arguments(FetchGroup.HEADERS_MASK, EnumSet.of(Profile.HEADERS)),
+            Arguments.arguments(FetchGroup.MIME_HEADERS_MASK, EnumSet.of(Profile.MIME_HEADERS)),
+            Arguments.arguments(FetchGroup.MIME_CONTENT_MASK, EnumSet.of(Profile.MIME_CONTENT)),
+            Arguments.arguments(FetchGroup.HEADERS_MASK | FetchGroup.MIME_CONTENT_MASK, EnumSet.of(Profile.HEADERS, Profile.MIME_CONTENT)));
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void ofContentShouldReturnCorrectValue(int content, EnumSet<Profile> expected) {
+        assertThat(Profile.of(content)).isEqualTo(expected);
+    }
+
     @Test
     void shouldMatchBeanContract() {
         EqualsVerifier.forClass(FetchGroup.class)
@@ -36,9 +61,8 @@ class FetchGroupTest {
 
     @Test
     void orShouldReturnAFetchGroupWithUpdatedContent() {
-        int expected = FetchGroup.HEADERS_MASK | FetchGroup.FULL_CONTENT_MASK;
         assertThat(FetchGroup.HEADERS.with(FetchGroup.FULL_CONTENT_MASK))
-            .isEqualTo(new FetchGroup(expected));
+            .isEqualTo(new FetchGroup(EnumSet.of(Profile.HEADERS, Profile.FULL_CONTENT)));
     }
 
     @Test
@@ -46,8 +70,9 @@ class FetchGroupTest {
         int[] path = {12};
         assertThat(
             FetchGroup.MINIMAL
-                .addPartContent(new MimePath(path), FetchGroup.MINIMAL_MASK))
-            .isEqualTo(new FetchGroup(FetchGroup.MINIMAL_MASK, ImmutableSet.of(new PartContentDescriptor(FetchGroup.MINIMAL_MASK, new MimePath(path)))));
+                .addPartContent(new MimePath(path), EnumSet.noneOf(Profile.class)))
+            .isEqualTo(new FetchGroup(EnumSet.noneOf(Profile.class),
+                ImmutableSet.of(new PartContentDescriptor(new MimePath(path)))));
     }
 
     @Test
@@ -56,11 +81,11 @@ class FetchGroupTest {
         int[] path2 = {13};
         assertThat(
             FetchGroup.MINIMAL
-                .addPartContent(new MimePath(path), FetchGroup.MINIMAL_MASK)
-                .addPartContent(new MimePath(path2), FetchGroup.MINIMAL_MASK))
-            .isEqualTo(new FetchGroup(FetchGroup.MINIMAL_MASK,
-                ImmutableSet.of(new PartContentDescriptor(FetchGroup.MINIMAL_MASK, new MimePath(path)),
-                    new PartContentDescriptor(FetchGroup.MINIMAL_MASK, new MimePath(path2)))));
+                .addPartContent(new MimePath(path), EnumSet.noneOf(Profile.class))
+                .addPartContent(new MimePath(path2), EnumSet.noneOf(Profile.class)))
+            .isEqualTo(new FetchGroup(EnumSet.noneOf(Profile.class),
+                ImmutableSet.of(new PartContentDescriptor(new MimePath(path)),
+                    new PartContentDescriptor(new MimePath(path2)))));
     }
 
     @Test
@@ -68,64 +93,9 @@ class FetchGroupTest {
         int[] path = {12};
         assertThat(
             FetchGroup.MINIMAL
-                .addPartContent(new MimePath(path), FetchGroup.MINIMAL_MASK)
-                .addPartContent(new MimePath(path), FetchGroup.HEADERS_MASK))
-            .isEqualTo(new FetchGroup(FetchGroup.MINIMAL_MASK, ImmutableSet.of(new PartContentDescriptor(FetchGroup.MINIMAL_MASK, new MimePath(path)).or(FetchGroup.HEADERS_MASK))));
-    }
-
-    @Test
-    void hasMaskShouldReturnFalseWhenNotContained() {
-        assertThat(FetchGroup.MINIMAL
-                .with(FetchGroup.MIME_HEADERS_MASK)
-                .with(FetchGroup.MIME_DESCRIPTOR_MASK)
-                .hasMask(FetchGroup.HEADERS_MASK))
-            .isFalse();
-    }
-
-    @Test
-    void hasMaskShouldReturnTrueWhenContained() {
-        assertThat(FetchGroup.MINIMAL
-                .with(FetchGroup.MIME_HEADERS_MASK)
-                .with(FetchGroup.MIME_DESCRIPTOR_MASK)
-                .hasMask(FetchGroup.MIME_HEADERS_MASK))
-            .isTrue();
-    }
-
-    @Test
-    void hasOnlyMasksShouldReturnTrueWhenSuppliedEmpty() {
-        assertThat(FetchGroup.MINIMAL
-                .hasOnlyMasks())
-            .isTrue();
-    }
-
-    @Test
-    void hasOnlyMasksShouldReturnTrueWhenExactlyContainASingleValue() {
-        assertThat(FetchGroup.HEADERS
-                .hasOnlyMasks(FetchGroup.HEADERS_MASK))
-            .isTrue();
-    }
-
-    @Test
-    void hasOnlyMasksShouldReturnTrueWhenExactlyContainMultipleValues() {
-        assertThat(FetchGroup.HEADERS
-                .with(FetchGroup.BODY_CONTENT_MASK)
-                .hasOnlyMasks(FetchGroup.HEADERS_MASK, FetchGroup.BODY_CONTENT_MASK))
-            .isTrue();
-    }
-
-    @Test
-    void hasOnlyMasksShouldReturnFalseWhenNotContained() {
-        assertThat(FetchGroup.HEADERS
-                .with(FetchGroup.BODY_CONTENT_MASK)
-                .hasOnlyMasks(FetchGroup.FULL_CONTENT_MASK))
-            .isFalse();
-    }
-
-    @Test
-    void minimalShouldAlwaysBeValid() {
-        assertThat(FetchGroup.MINIMAL
-                .hasOnlyMasks(FetchGroup.FULL_CONTENT_MASK, FetchGroup.HEADERS_MASK, FetchGroup.BODY_CONTENT_MASK,
-                    FetchGroup.MIME_DESCRIPTOR_MASK))
-            .isTrue();
+                .addPartContent(new MimePath(path), EnumSet.noneOf(Profile.class))
+                .addPartContent(new MimePath(path), EnumSet.of(Profile.HEADERS)))
+            .isEqualTo(new FetchGroup(EnumSet.noneOf(Profile.class),
+                ImmutableSet.of(new PartContentDescriptor(EnumSet.of(Profile.HEADERS), new MimePath(path)))));
     }
 }
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/PartContentDescriptorTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/PartContentDescriptorTest.java
index 5b0eb8c..ff9a817 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/PartContentDescriptorTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/PartContentDescriptorTest.java
@@ -19,37 +19,15 @@
 
 package org.apache.james.mailbox.model;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
 class PartContentDescriptorTest {
-    private static final int[] POSITION = {12};
-
     @Test
     void shouldMatchBeanContract() {
         EqualsVerifier.forClass(PartContentDescriptor.class)
             .withIgnoredFields("content")
             .verify();
     }
-
-    @Test
-    void hasMaskShouldReturnFalseWhenNotContained() {
-        assertThat(new PartContentDescriptor(new MimePath(POSITION))
-                .or(FetchGroup.MIME_HEADERS_MASK)
-                .or(FetchGroup.MIME_DESCRIPTOR_MASK)
-                .hasMask(FetchGroup.HEADERS_MASK))
-            .isFalse();
-    }
-
-    @Test
-    void hasMaskShouldReturnTrueWhenContained() {
-        assertThat(new PartContentDescriptor(new MimePath(POSITION))
-                .or(FetchGroup.MIME_HEADERS_MASK)
-                .or(FetchGroup.MIME_DESCRIPTOR_MASK)
-                .hasMask(FetchGroup.MIME_HEADERS_MASK))
-            .isTrue();
-    }
 }
\ No newline at end of file
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java
index 09e2c77..31efbfe 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.List;
 
 import org.apache.james.mailbox.exception.MailboxException;
@@ -43,6 +44,9 @@ import org.apache.james.mime4j.stream.RawField;
 import org.apache.james.mime4j.util.ByteSequence;
 import org.apache.james.mime4j.util.ContentUtil;
 
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+
 public class ResultUtils {
 
     public static List<Header> createHeaders(MailboxMessage document) throws IOException {
@@ -97,7 +101,7 @@ public class ResultUtils {
             MessageResultImpl messageResult = new MessageResultImpl(message);
             if (fetchGroup != null) {
                 if (!haveValidContent(fetchGroup)) {
-                    throw new UnsupportedOperationException("Unsupported result: " + fetchGroup.content());
+                    throw new UnsupportedOperationException("Unsupported result: " + fetchGroup.profiles());
                 }
                 addPartContent(fetchGroup, message, messageResult);
             }
@@ -107,11 +111,20 @@ public class ResultUtils {
         }
     }
 
-    private static boolean haveValidContent(FetchGroup fetchGroup) {
-        return fetchGroup.hasOnlyMasks(FetchGroup.HEADERS_MASK,
-            FetchGroup.BODY_CONTENT_MASK,
-            FetchGroup.FULL_CONTENT_MASK,
-            FetchGroup.MIME_DESCRIPTOR_MASK);
+    @VisibleForTesting
+    static boolean haveValidContent(FetchGroup fetchGroup) {
+        EnumSet<FetchGroup.Profile> supportedGroups = EnumSet.of(
+            FetchGroup.Profile.HEADERS,
+            FetchGroup.Profile.BODY_CONTENT,
+            FetchGroup.Profile.FULL_CONTENT,
+            FetchGroup.Profile.MIME_DESCRIPTOR);
+
+        Collection<FetchGroup.Profile> unsupportedProfiles = fetchGroup.profiles()
+            .stream()
+            .filter(value -> !supportedGroups.contains(value))
+            .collect(Guavate.toImmutableSet());
+
+        return unsupportedProfiles.isEmpty();
     }
 
     private static void addPartContent(FetchGroup fetchGroup, MailboxMessage message, MessageResultImpl messageResult)
@@ -127,19 +140,20 @@ public class ResultUtils {
     private static void addPartContent(PartContentDescriptor descriptor, MailboxMessage message, MessageResultImpl messageResult)
             throws MailboxException, IOException, MimeException {
         MimePath mimePath = descriptor.path();
-        if (descriptor.hasMask(FetchGroup.FULL_CONTENT_MASK)) {
+        EnumSet<FetchGroup.Profile> profiles = descriptor.profiles();
+        if (profiles.contains(FetchGroup.Profile.FULL_CONTENT)) {
             addFullContent(message, messageResult, mimePath);
         }
-        if (descriptor.hasMask(FetchGroup.BODY_CONTENT_MASK)) {
+        if (profiles.contains(FetchGroup.Profile.BODY_CONTENT)) {
             addBodyContent(message, messageResult, mimePath);
         }
-        if (descriptor.hasMask(FetchGroup.MIME_CONTENT_MASK)) {
+        if (profiles.contains(FetchGroup.Profile.MIME_CONTENT)) {
             addMimeBodyContent(message, messageResult, mimePath);
         }
-        if (descriptor.hasMask(FetchGroup.HEADERS_MASK)) {
+        if (profiles.contains(FetchGroup.Profile.HEADERS)) {
             addHeaders(message, messageResult, mimePath);
         }
-        if (descriptor.hasMask(FetchGroup.MIME_HEADERS_MASK)) {
+        if (profiles.contains(FetchGroup.Profile.MIME_HEADERS)) {
             addMimeHeaders(message, messageResult, mimePath);
         }
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/FetchGroupConverter.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/FetchGroupConverter.java
index 61bd4e1..1099c93 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/FetchGroupConverter.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/FetchGroupConverter.java
@@ -19,7 +19,10 @@
 
 package org.apache.james.mailbox.store.mail;
 
+import java.util.EnumSet;
+
 import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.FetchGroup.Profile;
 
 public class FetchGroupConverter {
     /**
@@ -27,27 +30,28 @@ public class FetchGroupConverter {
      * {@link MessageMapper.FetchType} for it
      */
     public static MessageMapper.FetchType getFetchType(FetchGroup group) {
-        if (group.hasMask(FetchGroup.FULL_CONTENT_MASK)) {
+        EnumSet<Profile> profiles = group.profiles();
+
+        if (profiles.contains(Profile.FULL_CONTENT)) {
             return MessageMapper.FetchType.Full;
         }
-        if (group.hasMask(FetchGroup.MIME_DESCRIPTOR_MASK)) {
-            // If we need the mimedescriptor we MAY need the full content later
-            // too.
+        if (profiles.contains(Profile.MIME_DESCRIPTOR)) {
+            // If we need the mimedescriptor we MAY need the full profile later too.
             // This gives us no other choice then request it
             return MessageMapper.FetchType.Full;
         }
-        if (group.hasMask(FetchGroup.MIME_CONTENT_MASK)) {
+        if (profiles.contains(Profile.MIME_CONTENT)) {
             return MessageMapper.FetchType.Full;
         }
-        if (group.hasMask(FetchGroup.MIME_HEADERS_MASK)) {
+        if (profiles.contains(Profile.MIME_HEADERS)) {
             return MessageMapper.FetchType.Full;
         }
         if (!group.getPartContentDescriptors().isEmpty()) {
             return MessageMapper.FetchType.Full;
         }
 
-        boolean headers = group.hasMask(FetchGroup.HEADERS_MASK);
-        boolean body = group.hasMask(FetchGroup.BODY_CONTENT_MASK);
+        boolean headers = profiles.contains(Profile.HEADERS);
+        boolean body = profiles.contains(Profile.BODY_CONTENT);
 
         if (body && headers) {
             return MessageMapper.FetchType.Full;
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/ResultUtilsTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/ResultUtilsTest.java
new file mode 100644
index 0000000..d122cbd
--- /dev/null
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/ResultUtilsTest.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.mailbox.store;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.stream.Stream;
+
+import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.FetchGroup.Profile;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class ResultUtilsTest {
+    static Stream<Arguments> haveValidContent() {
+        return Stream.of(
+            Arguments.of(FetchGroup.MINIMAL),
+            Arguments.of(FetchGroup.MINIMAL.with(Profile.MIME_DESCRIPTOR)),
+            Arguments.of(FetchGroup.FULL_CONTENT),
+            Arguments.of(FetchGroup.HEADERS),
+            Arguments.of(FetchGroup.BODY_CONTENT),
+            Arguments.of(FetchGroup.BODY_CONTENT.with(Profile.HEADERS)));
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void haveValidContent(FetchGroup fetchGroup) {
+        assertThat(ResultUtils.haveValidContent(fetchGroup)).isTrue();
+    }
+
+    static Stream<Arguments> haveInvalidContent() {
+        return Stream.of(
+            Arguments.of(FetchGroup.MINIMAL.with(Profile.MIME_CONTENT)),
+            Arguments.of(FetchGroup.MINIMAL.with(Profile.MIME_HEADERS)));
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void haveInvalidContent(FetchGroup fetchGroup) {
+        assertThat(ResultUtils.haveValidContent(fetchGroup)).isFalse();
+    }
+
+}
\ No newline at end of file
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/FetchGroupConverterTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/FetchGroupConverterTest.java
index ed93a81..0c1b376 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/FetchGroupConverterTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/FetchGroupConverterTest.java
@@ -21,9 +21,11 @@ package org.apache.james.mailbox.store.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.EnumSet;
 import java.util.stream.Stream;
 
 import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.FetchGroup.Profile;
 import org.apache.james.mailbox.model.MimePath;
 import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -43,10 +45,10 @@ class FetchGroupConverterTest {
             Arguments.arguments(FetchGroup.MINIMAL.with(FetchGroup.MIME_CONTENT_MASK), FetchType.Full),
             Arguments.arguments(FetchGroup.MINIMAL.with(FetchGroup.MIME_DESCRIPTOR_MASK), FetchType.Full),
             Arguments.arguments(FetchGroup.MINIMAL.with(FetchGroup.MIME_HEADERS_MASK), FetchType.Full),
-            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), FetchGroup.MINIMAL_MASK), FetchType.Full),
-            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), FetchGroup.HEADERS_MASK), FetchType.Full),
-            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), FetchGroup.BODY_CONTENT_MASK), FetchType.Full),
-            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), FetchGroup.FULL_CONTENT_MASK), FetchType.Full));
+            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), EnumSet.noneOf(Profile.class)), FetchType.Full),
+            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), EnumSet.of(Profile.HEADERS)), FetchType.Full),
+            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), EnumSet.of(Profile.BODY_CONTENT)), FetchType.Full),
+            Arguments.arguments(FetchGroup.MINIMAL.addPartContent(new MimePath(PARTS), EnumSet.of(Profile.FULL_CONTENT)), FetchType.Full));
     }
 
     @ParameterizedTest
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchDataConverter.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchDataConverter.java
index a75080a..baa4d92 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchDataConverter.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchDataConverter.java
@@ -20,6 +20,7 @@
 package org.apache.james.imap.processor.fetch;
 
 import java.util.Collection;
+import java.util.EnumSet;
 
 import org.apache.james.imap.api.message.BodyFetchElement;
 import org.apache.james.imap.api.message.FetchData;
@@ -32,10 +33,10 @@ class FetchDataConverter {
         FetchGroup result = FetchGroup.MINIMAL;
 
         if (fetch.isEnvelope()) {
-            result = result.with(FetchGroup.HEADERS_MASK);
+            result = result.with(FetchGroup.Profile.HEADERS);
         }
         if (fetch.isBody() || fetch.isBodyStructure()) {
-            result = result.with(FetchGroup.MIME_DESCRIPTOR_MASK);
+            result = result.with(FetchGroup.Profile.MIME_DESCRIPTOR);
         }
 
         Collection<BodyFetchElement> bodyElements = fetch.getBodyElements();
@@ -47,21 +48,21 @@ class FetchDataConverter {
                 switch (sectionType) {
                     case BodyFetchElement.CONTENT:
                         if (isBase) {
-                            result = addContent(result, path, isBase, FetchGroup.FULL_CONTENT_MASK);
+                            result = addContent(result, path, isBase, FetchGroup.Profile.FULL_CONTENT);
                         } else {
-                            result = addContent(result, path, isBase, FetchGroup.MIME_CONTENT_MASK);
+                            result = addContent(result, path, isBase, FetchGroup.Profile.MIME_CONTENT);
                         }
                         break;
                     case BodyFetchElement.HEADER:
                     case BodyFetchElement.HEADER_NOT_FIELDS:
                     case BodyFetchElement.HEADER_FIELDS:
-                        result = addContent(result, path, isBase, FetchGroup.HEADERS_MASK);
+                        result = addContent(result, path, isBase, FetchGroup.Profile.HEADERS);
                         break;
                     case BodyFetchElement.MIME:
-                        result = addContent(result, path, isBase, FetchGroup.MIME_HEADERS_MASK);
+                        result = addContent(result, path, isBase, FetchGroup.Profile.MIME_HEADERS);
                         break;
                     case BodyFetchElement.TEXT:
-                        result = addContent(result, path, isBase, FetchGroup.BODY_CONTENT_MASK);
+                        result = addContent(result, path, isBase, FetchGroup.Profile.BODY_CONTENT);
                         break;
                     default:
                         break;
@@ -72,12 +73,12 @@ class FetchDataConverter {
         return result;
     }
 
-    private static FetchGroup addContent(FetchGroup result, int[] path, boolean isBase, int content) {
+    private static FetchGroup addContent(FetchGroup result, int[] path, boolean isBase, FetchGroup.Profile profile) {
         if (isBase) {
-            return result.with(content);
+            return result.with(profile);
         } else {
             MimePath mimePath = new MimePath(path);
-            return result.addPartContent(mimePath, content);
+            return result.addPartContent(mimePath, EnumSet.of(profile));
         }
     }
 }
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/FetchDataConverterTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/FetchDataConverterTest.java
index 192cc26..f5b1cfa 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/FetchDataConverterTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/FetchDataConverterTest.java
@@ -23,15 +23,16 @@ import static org.apache.james.imap.api.message.BodyFetchElement.CONTENT;
 import static org.apache.james.imap.api.message.BodyFetchElement.HEADER;
 import static org.apache.james.imap.api.message.BodyFetchElement.MIME;
 import static org.apache.james.imap.api.message.BodyFetchElement.TEXT;
-import static org.apache.james.mailbox.model.FetchGroup.MIME_DESCRIPTOR_MASK;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.EnumSet;
 import java.util.stream.Stream;
 
 import org.apache.james.imap.api.ImapConstants;
 import org.apache.james.imap.api.message.BodyFetchElement;
 import org.apache.james.imap.api.message.FetchData;
 import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.FetchGroup.Profile;
 import org.apache.james.mailbox.model.MimePath;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -44,8 +45,8 @@ class FetchDataConverterTest {
     static Stream<Arguments> getFetchGroupShouldReturnCorrectValue() {
         return Stream.of(
             Arguments.arguments(new FetchData(), FetchGroup.MINIMAL),
-            Arguments.arguments(new FetchData().setBody(true), FetchGroup.MINIMAL.with(MIME_DESCRIPTOR_MASK)),
-            Arguments.arguments(new FetchData().setBodyStructure(true), FetchGroup.MINIMAL.with(MIME_DESCRIPTOR_MASK)),
+            Arguments.arguments(new FetchData().setBody(true), FetchGroup.MINIMAL.with(Profile.MIME_DESCRIPTOR)),
+            Arguments.arguments(new FetchData().setBodyStructure(true), FetchGroup.MINIMAL.with(Profile.MIME_DESCRIPTOR)),
             Arguments.arguments(new FetchData().setChangedSince(0L), FetchGroup.MINIMAL),
             Arguments.arguments(new FetchData().setEnvelope(true), FetchGroup.HEADERS),
             Arguments.arguments(new FetchData().setFlags(true), FetchGroup.MINIMAL),
@@ -57,17 +58,17 @@ class FetchDataConverterTest {
             Arguments.arguments(new FetchData().add(BodyFetchElement.createRFC822Header(), PEEK), FetchGroup.HEADERS),
             Arguments.arguments(new FetchData().add(BodyFetchElement.createRFC822Text(), PEEK), FetchGroup.BODY_CONTENT),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_HEADER, HEADER, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.HEADERS_MASK)),
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.HEADERS))),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, HEADER, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.BODY_CONTENT_MASK)),
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.BODY_CONTENT))),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, CONTENT, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.BODY_CONTENT_MASK)),
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.BODY_CONTENT))),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, CONTENT, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.MIME_CONTENT_MASK)),
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.MIME_CONTENT))),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, MIME, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.MIME_HEADERS_MASK)),
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.MIME_HEADERS))),
             Arguments.arguments(new FetchData().add(new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, TEXT, PATH, null, null, null), PEEK),
-                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), FetchGroup.BODY_CONTENT_MASK)));
+                FetchGroup.MINIMAL.addPartContent(new MimePath(PATH), EnumSet.of(Profile.BODY_CONTENT))));
     }
 
     @ParameterizedTest


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