JAMES-2530 [FILTERS] Complete POJOs, add tests and first draft of DTO

Based on Gautier work


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

Branch: refs/heads/master
Commit: 4d8e807e5414d26fd912aae7017760e32fe7c38e
Parents: 3b648e9
Author: Gautier DI FOLCO <gdifo...@linagora.com>
Authored: Thu Aug 23 10:18:01 2018 +0200
Committer: Benoit Tellier <btell...@linagora.com>
Committed: Tue Aug 28 12:48:15 2018 +0700

----------------------------------------------------------------------
 server/data/data-jmap-cassandra/pom.xml         |   5 +
 .../FilteringRuleSetDefineDTOModules.java       |   4 +-
 .../filtering/FilteringRuleSetDefinedDTO.java   |   4 +
 .../james/jmap/cassandra/filtering/RuleDTO.java |  68 ++++-
 .../james/jmap/cassandra/filtering/DTOTest.java | 114 ++++++++
 .../src/test/resources/json/event.json          |  23 ++
 .../src/test/resources/json/eventComplex.json   |  39 +++
 .../src/test/resources/json/eventEmpty.json     |   6 +
 .../jmap/api/filtering/FilteringManagement.java |  11 +
 .../apache/james/jmap/api/filtering/Rule.java   | 287 ++++++++++++++++++-
 .../filtering/FilteringManagementContract.java  |  78 +++--
 .../james/jmap/api/filtering/RuleFixture.java   |  71 +++++
 .../james/jmap/api/filtering/RuleTest.java      | 133 ++++++++-
 .../filtering/impl/DefineRulesCommandTest.java  |   5 +-
 14 files changed, 799 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/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 e9f4e85..67a479a 100644
--- a/server/data/data-jmap-cassandra/pom.xml
+++ b/server/data/data-jmap-cassandra/pom.xml
@@ -78,6 +78,11 @@
             <artifactId>javax.inject</artifactId>
         </dependency>
         <dependency>
+            <groupId>net.javacrumbs.json-unit</groupId>
+            <artifactId>json-unit-assertj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java
index 0c56b1c..2248eec 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java
@@ -24,11 +24,13 @@ import 
org.apache.james.jmap.api.filtering.impl.RuleSetDefined;
 
 public interface FilteringRuleSetDefineDTOModules {
 
+    String TYPE = "filtering-rule-set-defined";
+
     EventDTOModule<RuleSetDefined, FilteringRuleSetDefinedDTO> 
FILTERING_RULE_SET_DEFINED =
         EventDTOModule
             .forEvent(RuleSetDefined.class)
             .convertToDTO(FilteringRuleSetDefinedDTO.class)
             .convertWith(FilteringRuleSetDefinedDTO::from)
-            .typeName("filtering-rule-set-defined");
+            .typeName(TYPE);
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java
index 5a0de2c..0aa5bf6 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java
@@ -41,6 +41,10 @@ public class FilteringRuleSetDefinedDTO implements EventDTO {
             RuleDTO.from(event.getRules()));
     }
 
+    public static FilteringRuleSetDefinedDTO from(RuleSetDefined event) {
+        return from(event, FilteringRuleSetDefineDTOModules.TYPE);
+    }
+
     private final String type;
     private final int eventId;
     private final String aggregateId;

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
index a361465..c72eb39 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java
@@ -35,7 +35,7 @@ public class RuleDTO {
     public static ImmutableList<Rule> toRules(List<RuleDTO> ruleDTOList) {
         Preconditions.checkNotNull(ruleDTOList);
         return ruleDTOList.stream()
-                .map(dto -> Rule.of(dto.getId()))
+                .map(RuleDTO::toRule)
                 .collect(ImmutableList.toImmutableList());
     }
 
@@ -47,13 +47,33 @@ public class RuleDTO {
     }
 
     public static RuleDTO from(Rule rule) {
-        return new RuleDTO(rule.getId());
+        return new RuleDTO(rule.getId().asString(),
+                rule.getName(),
+                rule.getCondition().getField().asString(),
+                rule.getCondition().getComparator().asString(),
+                rule.getCondition().getValue(),
+                rule.getAction().getMailboxIds());
     }
 
     private final String id;
+    private final String name;
+    private final String field;
+    private final String comparator;
+    private final String value;
+    private final List<String> mailboxIds;
 
     @JsonCreator
-    public RuleDTO(@JsonProperty("id") String id) {
+    public RuleDTO(@JsonProperty("id") String id,
+                   @JsonProperty("name") String name,
+                   @JsonProperty("field") String field,
+                   @JsonProperty("comparator") String comparator,
+                   @JsonProperty("value") String value,
+                   @JsonProperty("mailboxIds") List<String> mailboxIds) {
+        this.name = name;
+        this.field = field;
+        this.comparator = comparator;
+        this.value = value;
+        this.mailboxIds = ImmutableList.copyOf(mailboxIds);
         Preconditions.checkNotNull(id);
 
         this.id = id;
@@ -63,19 +83,57 @@ public class RuleDTO {
         return id;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public String getField() {
+        return field;
+    }
+
+    public String getComparator() {
+        return comparator;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public List<String> getMailboxIds() {
+        return mailboxIds;
+    }
+
+    public Rule toRule() {
+        return Rule.builder()
+            .id(Rule.Id.of(id))
+            .name(name)
+            .condition(Rule.Condition.of(
+                Rule.Condition.Field.valueOf(field),
+                Rule.Condition.Comparator.of(comparator),
+                value))
+            .name(name)
+            .action(Rule.Action.ofMailboxIds(mailboxIds))
+            .build();
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof RuleDTO) {
             RuleDTO ruleDTO = (RuleDTO) o;
 
-            return Objects.equals(this.id, ruleDTO.id);
+            return Objects.equals(this.id, ruleDTO.id)
+                   && Objects.equals(this.name, ruleDTO.name)
+                   && Objects.equals(this.field, ruleDTO.field)
+                   && Objects.equals(this.comparator, ruleDTO.comparator)
+                   && Objects.equals(this.value, ruleDTO.value)
+                   && Objects.equals(this.mailboxIds, ruleDTO.mailboxIds);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
+        return Objects.hash(id, name, field, comparator, value, mailboxIds);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
 
b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
new file mode 100644
index 0000000..08f5685
--- /dev/null
+++ 
b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java
@@ -0,0 +1,114 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.cassandra.filtering;
+
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_FROM;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_RECIPIENT;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_SUBJECT;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_TO;
+import static org.assertj.core.api.Assertions.assertThat;
+import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.jmap.api.filtering.impl.FilteringAggregateId;
+import org.apache.james.jmap.api.filtering.impl.RuleSetDefined;
+import org.apache.james.util.ClassLoaderUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.guava.GuavaModule;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.google.common.collect.ImmutableList;
+
+public class DTOTest {
+    static final String EVENT_JSON = 
ClassLoaderUtils.getSystemResourceAsString("json/event.json");
+    static final String EVENT_EMPTY_JSON = 
ClassLoaderUtils.getSystemResourceAsString("json/eventEmpty.json");
+    static final String EVENT_COMPLEX_JSON = 
ClassLoaderUtils.getSystemResourceAsString("json/eventComplex.json");
+    static final FilteringRuleSetDefinedDTO SIMPLE_DTO = 
FilteringRuleSetDefinedDTO.from(
+            new RuleSetDefined(
+                    new FilteringAggregateId(User.fromUsername("Bart")),
+                    EventId.first(),
+                    ImmutableList.of(RULE_1, RULE_2)));
+    static final FilteringRuleSetDefinedDTO EMPTY_DTO = 
FilteringRuleSetDefinedDTO.from(
+            new RuleSetDefined(
+                    new FilteringAggregateId(User.fromUsername("Bart")),
+                    EventId.first(),
+                    ImmutableList.of()));
+    static final FilteringRuleSetDefinedDTO COMPLEX_DTO = 
FilteringRuleSetDefinedDTO.from(
+            new RuleSetDefined(
+                    new FilteringAggregateId(User.fromUsername("Bart")),
+                    EventId.first(),
+                    ImmutableList.of(RULE_FROM, RULE_RECIPIENT, RULE_SUBJECT, 
RULE_TO)));
+
+    private ObjectMapper objectMapper;
+
+    @BeforeEach
+    void setUp() {
+        objectMapper = new ObjectMapper();
+        objectMapper.registerModule(new Jdk8Module());
+        objectMapper.registerModule(new GuavaModule());
+    }
+
+    @Test
+    void shouldSerializeDTO() throws Exception {
+        String serializedEvent = objectMapper.writeValueAsString(SIMPLE_DTO);
+
+        assertThatJson(serializedEvent).isEqualTo(EVENT_JSON);
+    }
+
+    @Test
+    void shouldDeserializeDTO() throws Exception {
+        FilteringRuleSetDefinedDTO dto = objectMapper.readValue(EVENT_JSON, 
FilteringRuleSetDefinedDTO.class);
+
+        assertThat(dto).isEqualTo(SIMPLE_DTO);
+    }
+
+    @Test
+    void shouldSerializeEmptyDTO() throws Exception {
+        String serializedEvent = objectMapper.writeValueAsString(EMPTY_DTO);
+
+        assertThatJson(serializedEvent).isEqualTo(EVENT_EMPTY_JSON);
+    }
+
+    @Test
+    void shouldDeserializeEmptyDTO() throws Exception {
+        FilteringRuleSetDefinedDTO dto = 
objectMapper.readValue(EVENT_EMPTY_JSON, FilteringRuleSetDefinedDTO.class);
+
+        assertThat(dto).isEqualTo(EMPTY_DTO);
+    }
+
+    @Test
+    void shouldSerializeComplexDTO() throws Exception {
+        String serializedEvent = objectMapper.writeValueAsString(COMPLEX_DTO);
+
+        assertThatJson(serializedEvent).isEqualTo(EVENT_COMPLEX_JSON);
+    }
+
+    @Test
+    void shouldDeserializeComplexDTO() throws Exception {
+        FilteringRuleSetDefinedDTO dto = 
objectMapper.readValue(EVENT_COMPLEX_JSON, FilteringRuleSetDefinedDTO.class);
+
+        assertThat(dto).isEqualTo(COMPLEX_DTO);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/event.json
----------------------------------------------------------------------
diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/event.json 
b/server/data/data-jmap-cassandra/src/test/resources/json/event.json
new file mode 100644
index 0000000..b77e46a
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/event.json
@@ -0,0 +1,23 @@
+{
+  "type":"filtering-rule-set-defined",
+  "eventId":0,
+  "aggregateId":"FilteringRule/Bart",
+  "rules":[
+    {
+      "id":"1",
+      "name":"a name",
+      "field":"cc",
+      "comparator":"contains",
+      "value":"something",
+      "mailboxIds":["id-01"]
+    },
+    {
+      "id":"2",
+      "name":"a name",
+      "field":"cc",
+      "comparator":"contains",
+      "value":"something",
+      "mailboxIds":["id-01"]
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json 
b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json
new file mode 100644
index 0000000..a08e2d1
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json
@@ -0,0 +1,39 @@
+{
+  "type":"filtering-rule-set-defined",
+  "eventId":0,
+  "aggregateId":"FilteringRule/Bart",
+  "rules":[
+    {
+      "id":"id-from",
+      "name":"a name",
+      "field":"from",
+      "comparator":"contains",
+      "value":"A value to match 4",
+      "mailboxIds":["mbx1"]
+    },
+    {
+      "id":"id-rcpt",
+      "name":"a name",
+      "field":"recipient",
+      "comparator":"not-exactly-equals",
+      "value":"A value to match 3",
+      "mailboxIds":["mbx1"]
+    },
+    {
+      "id":"id-subject",
+      "name":"a name",
+      "field":"subject",
+      "comparator":"not-contains",
+      "value":"A value to match 2",
+      "mailboxIds":["mbx1"]
+    },
+    {
+      "id":"id-to",
+      "name":"a name",
+      "field":"to",
+      "comparator":"exactly-equals",
+      "value":"A value to match 1",
+      "mailboxIds":["mbx1"]
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json 
b/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json
new file mode 100644
index 0000000..f7fbaee
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json
@@ -0,0 +1,6 @@
+{
+  "type":"filtering-rule-set-defined",
+  "eventId":0,
+  "aggregateId":"FilteringRule/Bart",
+  "rules":[]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
index a8b1c4b..b39f691 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
@@ -19,14 +19,25 @@
 
 package org.apache.james.jmap.api.filtering;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.james.core.User;
 
+import com.google.common.collect.ImmutableList;
+
 public interface FilteringManagement {
 
     void defineRulesForUser(User user, List<Rule> rules);
 
+    default void defineRulesForUser(User user, Rule... rules) {
+        defineRulesForUser(user, Arrays.asList(rules));
+    }
+
+    default void clearRulesForUser(User user) {
+        defineRulesForUser(user, ImmutableList.of());
+    }
+
     List<Rule> listRulesForUser(User user);
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
index 8bca30a..0da600d 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
@@ -19,49 +19,318 @@
 
 package org.apache.james.jmap.api.filtering;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 
 public class Rule {
 
-    private final String id;
+    public static class Id {
+
+        public static Id of(String id) {
+            Preconditions.checkNotNull(id, "id should no be null");
+            Preconditions.checkArgument(StringUtils.isNotBlank(id), "id should 
no be empty");
+            return new Id(id);
+        }
+
+        private final String value;
+
+        private Id(String value) {
+            this.value = value;
+        }
+
+        public String asString() {
+            return value;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof Id) {
+                Id id = (Id) o;
+                return Objects.equals(value, id.value);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(value);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("value", value)
+                .toString();
+        }
+    }
+
+    public static class Condition {
+
+        public enum Field {
+            FROM("from"),
+            TO("to"),
+            CC("cc"),
+            SUBJECT("subject"),
+            RECIPIENT("recipient");
+            
+            public static Optional<Field> find(String fieldName) {
+                return Arrays.stream(values())
+                        .filter(value -> 
value.fieldName.equalsIgnoreCase(fieldName))
+                        .findAny();
+            }
+            
+            public static Field of(String fieldName) {
+                return find(fieldName).orElseThrow(() -> new 
IllegalStateException("'" + fieldName + "' is not a valid field name"));
+            }
+            
+            private final String fieldName;
+            
+            private Field(String fieldName) {
+                this.fieldName = fieldName;
+            }
+            
+            public String asString() {
+                return fieldName;
+            }
+        }
+        
+        public enum Comparator {
+            CONTAINS("contains"),
+            NOT_CONTAINS("not-contains"),
+            EXACTLY_EQUALS("exactly-equals"),
+            NOT_EXACTLY_EQUALS("not-exactly-equals");
+            
+            public static Optional<Comparator> find(String comparatorName) {
+                return Arrays.stream(values())
+                        .filter(value -> 
value.comparatorName.equalsIgnoreCase(comparatorName))
+                        .findAny();
+            }
+            
+            public static Comparator of(String comparatorName) {
+                return find(comparatorName).orElseThrow(() -> new 
IllegalStateException("'" + comparatorName + "' is not a valid comparator 
name"));
+            }
+            
+            private final String comparatorName;
+            
+            private Comparator(String comparator) {
+                this.comparatorName = comparator;
+            }
+            
+            public String asString() {
+                return comparatorName;
+            }
+        }
+
+        public static Condition of(Field field, Comparator comparator, String 
value) {
+            Preconditions.checkNotNull(field, "field should no be null");
+            Preconditions.checkNotNull(comparator, "comparator should no be 
null");
+            Preconditions.checkNotNull(value, "value should no be null");
+            Preconditions.checkArgument(StringUtils.isNotBlank(value), "value 
should no be empty");
+            return new Condition(field, comparator, value);
+        }
+
+        private final Field field;
+        private final Comparator comparator;
+        private final String value;
+
+        private Condition(Field field, Comparator comparator, String value) {
+            this.field = field;
+            this.comparator = comparator;
+            this.value = value;
+        }
+        
+        public Field getField() {
+            return field;
+        }
+        
+        public Comparator getComparator() {
+            return comparator;
+        }
+        
+        public String getValue() {
+            return value;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof Condition) {
+                Condition condition = (Condition) o;
+                return Objects.equals(field, condition.field)
+                    && Objects.equals(comparator, condition.comparator)
+                    && Objects.equals(value, condition.value);
+            }
+            return false;
+        }
 
-    public static Rule of(String id) {
-        return new Rule(id);
+        @Override
+        public final int hashCode() {
+            return Objects.hash(field, comparator, value);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("field", field)
+                .add("comparator", comparator)
+                .add("value", value)
+                .toString();
+        }
     }
 
-    public Rule(String id) {
-        Preconditions.checkNotNull(id);
 
+    public static class Action {
+
+        public static Action ofMailboxIds(List<String> mailboxIds) {
+            Preconditions.checkNotNull(mailboxIds, "mailboxIds should no be 
null");
+            return new Action(mailboxIds);
+        }
+
+        public static Action ofMailboxIds(String... mailboxIds) {
+            return ofMailboxIds(Arrays.asList(mailboxIds));
+        }
+
+        private final ImmutableList<String> mailboxIds;
+
+        private Action(List<String> mailboxIds) {
+            this.mailboxIds = ImmutableList.copyOf(mailboxIds);
+        }
+        
+        public ImmutableList<String> getMailboxIds() {
+            return mailboxIds;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof Action) {
+                Action action = (Action) o;
+                return Objects.equals(mailboxIds, action.mailboxIds);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(mailboxIds);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("mailboxIds", mailboxIds)
+                .toString();
+        }
+    }
+
+    public static class Builder {
+
+        private Optional<Id> id;
+        private Optional<String> name;
+        private Optional<Condition> condition;
+        private Optional<Action> action;
+
+        public Builder() {
+            this.id = Optional.empty();
+            this.name = Optional.empty();
+            this.condition = Optional.empty();
+            this.action = Optional.empty();
+        }
+
+        public Builder id(Id id) {
+            this.id = Optional.of(id);
+            return this;
+        }
+
+        public Builder name(String name) {
+            this.name = Optional.of(name);
+            return this;
+        }
+
+        public Builder condition(Condition condition) {
+            this.condition = Optional.of(condition);
+            return this;
+        }
+
+        public Builder action(Action action) {
+            this.action = Optional.of(action);
+            return this;
+        }
+
+        public Rule build() {
+            Preconditions.checkState(id.isPresent(), "`id` is mandatory");
+            Preconditions.checkState(name.isPresent(), "`name` is mandatory");
+            Preconditions.checkState(condition.isPresent(), "`condition` is 
mandatory");
+            Preconditions.checkState(action.isPresent(), "`action` is 
mandatory");
+
+            return new Rule(id.get(), name.get(), condition.get(), 
action.get());
+        }
+
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private final Id id;
+    private final String name;
+    private final Condition condition;
+    private final Action action;
+
+    public Rule(Id id, String name, Condition condition, Action action) {
         this.id = id;
+        this.name = name;
+        this.condition = condition;
+        this.action = action;
     }
 
-    public String getId() {
+    public Id getId() {
         return id;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public Condition getCondition() {
+        return condition;
+    }
+
+    public Action getAction() {
+        return action;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof Rule) {
             Rule rule = (Rule) o;
 
-            return Objects.equals(this.id, rule.id);
+            return Objects.equals(this.id, rule.id)
+                && Objects.equals(this.name, rule.name)
+                && Objects.equals(this.condition, rule.condition)
+                && Objects.equals(this.action, rule.action);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
+        return Objects.hash(id, name, condition, action);
     }
 
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
             .add("id", id)
+            .add("name", name)
+            .add("condition", condition)
+            .add("action", action)
             .toString();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
index dd2f773..a28cbff 100644
--- 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
@@ -18,22 +18,27 @@
  ****************************************************************/
 package org.apache.james.jmap.api.filtering;
 
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_3;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_FROM;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_RECIPIENT;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_SUBJECT;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_TO;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import java.util.List;
+
 import org.apache.james.core.User;
 import org.apache.james.eventsourcing.eventstore.EventStore;
 import 
org.apache.james.jmap.api.filtering.impl.EventSourcingFilteringManagement;
 import org.junit.jupiter.api.Test;
 
-import com.google.common.collect.ImmutableList;
-
 public interface FilteringManagementContract {
 
     String BART_SIMPSON_CARTOON = "bart@simpson.cartoon";
-    Rule RULE_1 = Rule.of("1");
-    Rule RULE_2 = Rule.of("2");
-    Rule RULE_3 = Rule.of("3");
+    User USER = User.fromUsername(BART_SIMPSON_CARTOON);
 
     default FilteringManagement instanciateFilteringManagement(EventStore 
eventStore) {
         return new EventSourcingFilteringManagement(eventStore);
@@ -41,71 +46,90 @@ public interface FilteringManagementContract {
 
     @Test
     default void listingRulesForUnknownUserShouldReturnEmptyList(EventStore 
eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
-        
assertThat(instanciateFilteringManagement(eventStore).listRulesForUser(user)).isEmpty();
+        
assertThat(instanciateFilteringManagement(eventStore).listRulesForUser(USER))
+            .isEmpty();
     }
 
     @Test
     default void listingRulesShouldThrowWhenNullUser(EventStore eventStore) {
         User user = null;
-        assertThatThrownBy(() -> 
instanciateFilteringManagement(eventStore).listRulesForUser(user)).isInstanceOf(NullPointerException.class);
+        assertThatThrownBy(() -> 
instanciateFilteringManagement(eventStore).listRulesForUser(user))
+            .isInstanceOf(NullPointerException.class);
     }
 
     @Test
     default void listingRulesShouldReturnDefinedRules(EventStore eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2));
-        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_1, 
RULE_2);
+
+        testee.defineRulesForUser(USER, RULE_1, RULE_2);
+
+        assertThat(testee.listRulesForUser(USER))
+            .containsExactly(RULE_1, RULE_2);
     }
 
     @Test
     default void listingRulesShouldReturnLastDefinedRules(EventStore 
eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2));
-        testee.defineRulesForUser(user, ImmutableList.of(RULE_2, RULE_1));
-        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_2, 
RULE_1);
+
+        testee.defineRulesForUser(USER, RULE_1, RULE_2);
+        testee.defineRulesForUser(USER, RULE_2, RULE_1);
+
+        assertThat(testee.listRulesForUser(USER))
+            .containsExactly(RULE_2, RULE_1);
     }
 
     @Test
     default void definingRulesShouldThrowWhenDuplicateRules(EventStore 
eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        assertThatThrownBy(() -> testee.defineRulesForUser(user, 
ImmutableList.of(RULE_1, RULE_1)))
+
+        assertThatThrownBy(() -> testee.defineRulesForUser(USER, RULE_1, 
RULE_1))
             .isInstanceOf(IllegalArgumentException.class);
     }
 
     @Test
     default void definingRulesShouldThrowWhenNullUser(EventStore eventStore) {
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        assertThatThrownBy(() -> testee.defineRulesForUser(null, 
ImmutableList.of(RULE_1, RULE_1)))
+
+        assertThatThrownBy(() -> testee.defineRulesForUser(null, RULE_1, 
RULE_1))
             .isInstanceOf(NullPointerException.class);
     }
 
     @Test
     default void definingRulesShouldThrowWhenNullRuleList(EventStore 
eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        assertThatThrownBy(() -> testee.defineRulesForUser(user, null))
+
+        List<Rule> rules = null;
+        assertThatThrownBy(() -> testee.defineRulesForUser(USER, rules))
             .isInstanceOf(NullPointerException.class);
     }
 
     @Test
     default void definingRulesShouldKeepOrdering(EventStore eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, 
RULE_1));
-        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_3, 
RULE_2, RULE_1);
+        testee.defineRulesForUser(USER, RULE_3, RULE_2, RULE_1);
+
+        assertThat(testee.listRulesForUser(USER))
+            .containsExactly(RULE_3, RULE_2, RULE_1);
     }
 
     @Test
     default void definingEmptyRuleListShouldRemoveExistingRules(EventStore 
eventStore) {
-        User user = User.fromUsername(BART_SIMPSON_CARTOON);
         FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
-        testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, 
RULE_1));
-        testee.defineRulesForUser(user, ImmutableList.of());
-        assertThat(testee.listRulesForUser(user)).isEmpty();
+
+        testee.defineRulesForUser(USER, RULE_3, RULE_2, RULE_1);
+        testee.clearRulesForUser(USER);
+
+        assertThat(testee.listRulesForUser(USER)).isEmpty();
+    }
+
+    @Test
+    default void allFieldsAndComparatorShouldWellBeStored(EventStore 
eventStore) {
+        FilteringManagement testee = 
instanciateFilteringManagement(eventStore);
+
+        testee.defineRulesForUser(USER, RULE_FROM, RULE_RECIPIENT, 
RULE_SUBJECT, RULE_TO, RULE_1);
+
+        assertThat(testee.listRulesForUser(USER))
+            .containsExactly(RULE_FROM, RULE_RECIPIENT, RULE_SUBJECT, RULE_TO, 
RULE_1);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
new file mode 100644
index 0000000..5d17d03
--- /dev/null
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java
@@ -0,0 +1,71 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.api.filtering;
+
+public interface RuleFixture {
+    String NAME = "a name";
+    Rule.Condition CONDITION = Rule.Condition.of(Rule.Condition.Field.CC, 
Rule.Condition.Comparator.CONTAINS, "something");
+    Rule.Action ACTION = Rule.Action.ofMailboxIds("id-01");
+    Rule.Builder RULE_BUILER = 
Rule.builder().name(NAME).condition(CONDITION).action(ACTION);
+    Rule RULE_1 = RULE_BUILER.id(Rule.Id.of("1")).build();
+    Rule RULE_2 = RULE_BUILER.id(Rule.Id.of("2")).build();
+    Rule RULE_3 = RULE_BUILER.id(Rule.Id.of("3")).build();
+
+    Rule RULE_TO = Rule.builder()
+            .id(Rule.Id.of("id-to"))
+            .name(NAME)
+            .action(Rule.Action.ofMailboxIds("mbx1"))
+            .condition(Rule.Condition.of(
+                    Rule.Condition.Field.TO,
+                    Rule.Condition.Comparator.EXACTLY_EQUALS,
+                    "A value to match 1"))
+            .build();
+
+    Rule RULE_SUBJECT = Rule.builder()
+            .id(Rule.Id.of("id-subject"))
+            .name(NAME)
+            .action(Rule.Action.ofMailboxIds("mbx1"))
+            .condition(Rule.Condition.of(
+                    Rule.Condition.Field.SUBJECT,
+                    Rule.Condition.Comparator.NOT_CONTAINS,
+                    "A value to match 2"))
+            .build();
+
+    Rule RULE_RECIPIENT = Rule.builder()
+            .id(Rule.Id.of("id-rcpt"))
+            .name(NAME)
+            .action(Rule.Action.ofMailboxIds("mbx1"))
+            .condition(Rule.Condition.of(
+                    Rule.Condition.Field.RECIPIENT,
+                    Rule.Condition.Comparator.NOT_EXACTLY_EQUALS,
+                    "A value to match 3"))
+            .build();
+
+    Rule RULE_FROM = Rule.builder()
+            .id(Rule.Id.of("id-from"))
+            .name(NAME)
+            .action(Rule.Action.ofMailboxIds("mbx1"))
+            .condition(Rule.Condition.of(
+                    Rule.Condition.Field.FROM,
+                    Rule.Condition.Comparator.CONTAINS,
+                    "A value to match 4"))
+            .build();
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
index fc10f6a..2e3e760 100644
--- 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
@@ -19,13 +19,25 @@
 
 package org.apache.james.jmap.api.filtering;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
-class RuleTest {
+public class RuleTest {
+
+    private static final List<String> ACTION_MAILBOXIDS = 
Arrays.asList("id-01");
+    private static final String CONDITION_COMPARATOR = "contains";
+    private static final String CONDITION_FIELD = "cc";
+    private static final String NAME = "a name";
+    public static final Rule.Condition CONDITION = 
Rule.Condition.of(Rule.Condition.Field.of(CONDITION_FIELD), 
Rule.Condition.Comparator.of(CONDITION_COMPARATOR), "something");
+    public static final Rule.Action ACTION = 
Rule.Action.ofMailboxIds(ACTION_MAILBOXIDS);
+    public static final Rule.Id UNIQUE_ID = Rule.Id.of("uniqueId");
 
     @Test
     void shouldMatchBeanContract() {
@@ -34,8 +46,119 @@ class RuleTest {
     }
 
     @Test
-    void constructorShouldThrowWhenNullId() {
-        assertThatThrownBy(() -> new Rule(null))
-            .isInstanceOf(NullPointerException.class);
+    void innerClassConditionShouldMatchBeanContract() {
+        EqualsVerifier.forClass(Rule.Condition.class)
+            .verify();
+    }
+
+    @Test
+    void innerClassActionShouldMatchBeanContract() {
+        EqualsVerifier.forClass(Rule.Action.class)
+            .verify();
+    }
+
+    @Test
+    void innerClassIdShouldMatchBeanContract() {
+        EqualsVerifier.forClass(Rule.Id.class)
+            .verify();
+    }
+
+    @Test
+    void idShouldThrowOnNull() {
+        assertThatThrownBy(() -> 
Rule.Id.of(null)).isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    void idShouldThrowOnEmpty() {
+        assertThatThrownBy(() -> 
Rule.Id.of("")).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void idShouldThrowOnBlank() {
+        assertThatThrownBy(() -> Rule.Id.of("   
")).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void idShouldBeMandatory() {
+        assertThatThrownBy(() ->
+            Rule.builder()
+                .name(NAME)
+                .condition(CONDITION)
+                .action(ACTION)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    void nameShouldBeMandatory() {
+        assertThatThrownBy(() ->
+            Rule.builder()
+                .id(UNIQUE_ID)
+                .condition(CONDITION)
+                .action(ACTION)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    void conditionShouldBeMandatory() {
+        assertThatThrownBy(() ->
+            Rule.builder()
+                .id(UNIQUE_ID)
+                .name(NAME)
+                .action(ACTION)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    void actionShouldBeMandatory() {
+        assertThatThrownBy(() ->
+            Rule.builder()
+                .id(UNIQUE_ID)
+                .name(NAME)
+                .condition(CONDITION)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
     }
-}
\ No newline at end of file
+
+    @Test
+    void builderShouldPreserveCondition() {
+        Rule rule = Rule.builder()
+            .id(UNIQUE_ID)
+            .name(NAME)
+            .condition(CONDITION)
+            .action(ACTION)
+            .build();
+
+        assertThat(rule.getCondition()).isEqualTo(CONDITION);
+    }
+
+    @Test
+    void builderShouldPreserveAction() {
+        Rule rule = Rule.builder()
+            .id(UNIQUE_ID)
+            .name(NAME)
+            .condition(CONDITION)
+            .action(ACTION)
+            .build();
+
+        assertThat(rule.getAction()).isEqualTo(ACTION);
+    }
+
+    @Test
+    void buildConditionShouldConserveField() {
+        assertThat(CONDITION.getField().asString()).isEqualTo(CONDITION_FIELD);
+    }
+
+    @Test
+    void buildConditionShouldConserveComparator() {
+        
assertThat(CONDITION.getComparator().asString()).isEqualTo(CONDITION_COMPARATOR);
+    }
+
+    @Test
+    void buildActionShouldConserveMailboxIdsList() {
+        assertThat(ACTION.getMailboxIds()).isEqualTo(ACTION_MAILBOXIDS);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
index a917fdd..2fa75c0 100644
--- 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
@@ -19,10 +19,11 @@
 
 package org.apache.james.jmap.api.filtering.impl;
 
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1;
+import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import org.apache.james.core.User;
-import org.apache.james.jmap.api.filtering.Rule;
 import org.junit.jupiter.api.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -39,7 +40,7 @@ class DefineRulesCommandTest {
 
     @Test
     void constructorShouldThrowWhenNullUser() {
-        assertThatThrownBy(() -> new DefineRulesCommand(null, 
ImmutableList.of(Rule.of("1"), Rule.of("2"))))
+        assertThatThrownBy(() -> new DefineRulesCommand(null, 
ImmutableList.of(RULE_1, RULE_2)))
             .isInstanceOf(NullPointerException.class);
     }
 


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

Reply via email to