JAMES-2420 DLP rule store API, contract & event sourcing implementation


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

Branch: refs/heads/master
Commit: 3f368fc7c870e15f254f2fc97359e1d9c678d775
Parents: 18ab2d4
Author: benwa <btell...@linagora.com>
Authored: Fri Jun 8 17:15:48 2018 +0700
Committer: benwa <btell...@linagora.com>
Committed: Thu Jun 14 15:22:58 2018 +0700

----------------------------------------------------------------------
 .../james/eventsourcing/CommandDispatcher.java  |   2 +-
 .../apache/james/eventsourcing/EventBus.java    |   5 +-
 server/data/data-api/pom.xml                    |   6 +-
 .../james/dlp/api/DLPConfigurationItem.java     | 185 +++++++++++++++++++
 .../james/dlp/api/DLPConfigurationStore.java    |  41 ++++
 .../james/dlp/api/DLPConfigurationItemTest.java | 162 ++++++++++++++++
 .../dlp/api/DLPConfigurationStoreContract.java  | 101 ++++++++++
 .../org/apache/james/dlp/api/DLPFixture.java    |  34 ++++
 server/data/data-library/pom.xml                |  10 +
 .../EventSourcingDLPConfigurationStore.java     |  81 ++++++++
 .../aggregates/DLPAggregateId.java              |  60 ++++++
 .../aggregates/DLPDomainConfiguration.java      | 151 +++++++++++++++
 .../eventsourcing/commands/ClearCommand.java    |  64 +++++++
 .../commands/ClearCommandHandler.java           |  52 ++++++
 .../eventsourcing/commands/StoreCommand.java    |  75 ++++++++
 .../commands/StoreCommandHandler.java           |  52 ++++++
 .../events/ConfigurationItemsAdded.java         |  89 +++++++++
 .../events/ConfigurationItemsRemoved.java       |  91 +++++++++
 .../aggregates/DLPAggregateIdTest.java          |  51 +++++
 .../commands/ClearCommandTest.java              |  43 +++++
 .../commands/StoreCommandTest.java              |  53 ++++++
 .../events/ConfigurationItemsAddedTest.java     |  67 +++++++
 .../events/ConfigurationItemsRemovedTest.java   |  67 +++++++
 server/data/data-memory/pom.xml                 |  11 ++
 .../EventSourcingDLPConfigurationStoreTest.java |  28 +++
 ...tSourcingDLPConfigurationStoreExtension.java |  40 ++++
 26 files changed, 1615 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/CommandDispatcher.java
----------------------------------------------------------------------
diff --git 
a/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/CommandDispatcher.java
 
b/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/CommandDispatcher.java
index 15d128c..14498ae 100644
--- 
a/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/CommandDispatcher.java
+++ 
b/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/CommandDispatcher.java
@@ -86,7 +86,7 @@ public class CommandDispatcher {
             .orElseThrow(() -> new TooManyRetries(c, MAX_RETRY));
     }
 
-    public Optional<Integer> trySeveralTimes(Supplier<Boolean> singleTry) {
+    private Optional<Integer> trySeveralTimes(Supplier<Boolean> singleTry) {
         return IntStream.range(0, MAX_RETRY)
             .boxed()
             .filter(any -> singleTry.get())

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/EventBus.java
----------------------------------------------------------------------
diff --git 
a/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/EventBus.java
 
b/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/EventBus.java
index 289433e..22b817f 100644
--- 
a/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/EventBus.java
+++ 
b/event-sourcing/event-sourcing-core/src/main/java/org/apache/james/eventsourcing/EventBus.java
@@ -34,7 +34,8 @@ import com.google.common.collect.ImmutableSet;
 
 public class EventBus {
 
-    public static final Logger LOGGER = 
LoggerFactory.getLogger(EventBus.class);
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(EventBus.class);
+
     private final EventStore eventStore;
     private final Set<Subscriber> subscribers;
 
@@ -51,7 +52,7 @@ public class EventBus {
             .forEach(this::handle);
     }
 
-    public void handle(Pair<Event, Subscriber> pair) {
+    private void handle(Pair<Event, Subscriber> pair) {
         Subscriber subscriber = pair.getRight();
         Event event = pair.getLeft();
         try {

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-api/pom.xml b/server/data/data-api/pom.xml
index 7a58cfc..26de148 100644
--- a/server/data/data-api/pom.xml
+++ b/server/data/data-api/pom.xml
@@ -34,13 +34,13 @@
 
     <dependencies>
         <dependency>
+            <!-- only used by JamesUser (for MailAddress) -->
             <groupId>${project.groupId}</groupId>
-            <artifactId>james-core</artifactId>
+            <artifactId>apache-mailet-api</artifactId>
         </dependency>
         <dependency>
-            <!-- only used by JamesUser (for MailAddress) -->
             <groupId>${project.groupId}</groupId>
-            <artifactId>apache-mailet-api</artifactId>
+            <artifactId>james-core</artifactId>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationItem.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationItem.java
 
b/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationItem.java
new file mode 100644
index 0000000..bda1c24
--- /dev/null
+++ 
b/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationItem.java
@@ -0,0 +1,185 @@
+/****************************************************************
+ * 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.dlp.api;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class DLPConfigurationItem {
+
+    public static class Builder {
+        private static final boolean NOT_TARGETED = false;
+
+        private Optional<Boolean> targetsSender;
+        private Optional<Boolean> targetsRecipients;
+        private Optional<Boolean> targetsContent;
+        private Optional<String> explanation;
+        private Optional<String> expression;
+
+        public Builder() {
+            targetsSender = Optional.empty();
+            targetsRecipients = Optional.empty();
+            targetsContent = Optional.empty();
+            explanation = Optional.empty();
+            expression = Optional.empty();
+        }
+
+        public Builder targetsSender() {
+            this.targetsSender = Optional.of(true);
+            return this;
+        }
+
+        public Builder targetsRecipients() {
+            this.targetsRecipients = Optional.of(true);
+            return this;
+        }
+
+        public Builder targetsContent() {
+            this.targetsContent = Optional.of(true);
+            return this;
+        }
+
+        public Builder expression(String expression) {
+            this.expression = Optional.of(expression);
+            return this;
+        }
+
+        public Builder explanation(String explanation) {
+            this.explanation = Optional.of(explanation);
+            return this;
+        }
+
+        public DLPConfigurationItem build() {
+            Preconditions.checkState(expression.isPresent(), "`expression` is 
mandatory");
+            return new DLPConfigurationItem(
+                explanation,
+                expression.get(),
+                new Targets(
+                    targetsSender.orElse(NOT_TARGETED),
+                    targetsRecipients.orElse(NOT_TARGETED),
+                    targetsContent.orElse(NOT_TARGETED)));
+        }
+    }
+
+    public static class Targets {
+        private final boolean senderTargeted;
+        private final boolean recipientTargeted;
+        private final boolean contentTargeted;
+
+        public Targets(boolean senderTargeted, boolean recipientTargeted, 
boolean contentTargeted) {
+            this.senderTargeted = senderTargeted;
+            this.recipientTargeted = recipientTargeted;
+            this.contentTargeted = contentTargeted;
+        }
+
+        public boolean isSenderTargeted() {
+            return senderTargeted;
+        }
+
+        public boolean isRecipientTargeted() {
+            return recipientTargeted;
+        }
+
+        public boolean isContentTargeted() {
+            return contentTargeted;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof Targets) {
+                Targets targets = (Targets) o;
+
+                return Objects.equals(this.senderTargeted, 
targets.senderTargeted)
+                    && Objects.equals(this.recipientTargeted, 
targets.recipientTargeted)
+                    && Objects.equals(this.contentTargeted, 
targets.contentTargeted);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(senderTargeted, recipientTargeted, 
contentTargeted);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("senderTargeted", senderTargeted)
+                .add("recipientTargeted", recipientTargeted)
+                .add("contentTargeted", contentTargeted)
+                .toString();
+        }
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private final Optional<String> explanation;
+    private final String regexp;
+    private final Targets targets;
+
+    private DLPConfigurationItem(Optional<String> explanation, String regexp, 
Targets targets) {
+        this.explanation = explanation;
+        this.regexp = regexp;
+        this.targets = targets;
+    }
+
+    public Optional<String> getExplanation() {
+        return explanation;
+    }
+
+    public String getRegexp() {
+        return regexp;
+    }
+
+    public Targets getTargets() {
+        return targets;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof DLPConfigurationItem) {
+            DLPConfigurationItem dlpConfigurationItem = (DLPConfigurationItem) 
o;
+
+            return Objects.equals(this.explanation, 
dlpConfigurationItem.explanation)
+                && Objects.equals(this.regexp, dlpConfigurationItem.regexp)
+                && Objects.equals(this.targets, dlpConfigurationItem.targets);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(explanation, regexp, targets);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("explanation", explanation)
+            .add("regexp", regexp)
+            .add("targets", targets)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationStore.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationStore.java
 
b/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationStore.java
new file mode 100644
index 0000000..457341e
--- /dev/null
+++ 
b/server/data/data-api/src/main/java/org/apache/james/dlp/api/DLPConfigurationStore.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.james.dlp.api;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.james.core.Domain;
+
+import com.google.common.collect.ImmutableList;
+
+public interface DLPConfigurationStore {
+
+    Stream<DLPConfigurationItem> list(Domain domain);
+
+    void store(Domain domain, List<DLPConfigurationItem> rule);
+
+    default void store(Domain domain, DLPConfigurationItem rule) {
+        store(domain, ImmutableList.of(rule));
+    }
+
+    void clear(Domain domain);
+    
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationItemTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationItemTest.java
 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationItemTest.java
new file mode 100644
index 0000000..4a38bf1
--- /dev/null
+++ 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationItemTest.java
@@ -0,0 +1,162 @@
+/****************************************************************
+ * 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.dlp.api;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class DLPConfigurationItemTest {
+
+    private static final String EXPLANATION = "explanation";
+    private static final String REGEX = "regex";
+
+    @Test
+    void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(DLPConfigurationItem.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    void innerClassTargetsShouldMatchBeanContract() {
+        EqualsVerifier.forClass(DLPConfigurationItem.Targets.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    void expressionShouldBeMandatory() {
+        assertThatThrownBy(() ->
+            DLPConfigurationItem.builder()
+                .targetsRecipients()
+                .targetsSender()
+                .targetsContent()
+                .explanation(EXPLANATION)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    void expressionShouldBeTheOnlyMandatoryField() {
+        assertThatCode(() ->
+            DLPConfigurationItem.builder()
+                .expression(REGEX)
+                .build())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void builderShouldPreserveExpression() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .expression(REGEX)
+            .build();
+
+        assertThat(dlpConfigurationItem.getRegexp()).isEqualTo(REGEX);
+    }
+
+    @Test
+    void builderShouldPreserveExplanation() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .explanation(EXPLANATION)
+            .expression(REGEX)
+            .build();
+
+        
assertThat(dlpConfigurationItem.getExplanation()).contains(EXPLANATION);
+    }
+
+    @Test
+    void dlpRuleShouldHaveNoTargetsWhenNoneSpecified() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .expression(REGEX)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(dlpConfigurationItem.getTargets().isContentTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isRecipientTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isSenderTargeted()).isFalse();
+        });
+    }
+
+    @Test
+    void targetsRecipientsShouldBeReportedInTargets() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .targetsRecipients()
+            .expression(REGEX)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(dlpConfigurationItem.getTargets().isContentTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isRecipientTargeted()).isTrue();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isSenderTargeted()).isFalse();
+        });
+    }
+
+    @Test
+    void targetsSenderShouldBeReportedInTargets() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .targetsSender()
+            .expression(REGEX)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(dlpConfigurationItem.getTargets().isContentTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isRecipientTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isSenderTargeted()).isTrue();
+        });
+    }
+
+    @Test
+    void targetsContentShouldBeReportedInTargets() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .targetsContent()
+            .expression(REGEX)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(dlpConfigurationItem.getTargets().isContentTargeted()).isTrue();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isRecipientTargeted()).isFalse();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isSenderTargeted()).isFalse();
+        });
+    }
+
+    @Test
+    void allTargetsShouldBeReportedInTargets() {
+        DLPConfigurationItem dlpConfigurationItem = 
DLPConfigurationItem.builder()
+            .targetsContent()
+            .targetsSender()
+            .targetsRecipients()
+            .expression(REGEX)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(dlpConfigurationItem.getTargets().isContentTargeted()).isTrue();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isRecipientTargeted()).isTrue();
+            
softly.assertThat(dlpConfigurationItem.getTargets().isSenderTargeted()).isTrue();
+        });
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationStoreContract.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationStoreContract.java
 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationStoreContract.java
new file mode 100644
index 0000000..fa506b7
--- /dev/null
+++ 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPConfigurationStoreContract.java
@@ -0,0 +1,101 @@
+/****************************************************************
+ * 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.dlp.api;
+
+import static org.apache.james.dlp.api.DLPFixture.RULE;
+import static org.apache.james.dlp.api.DLPFixture.RULE_2;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import org.apache.james.core.Domain;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public interface DLPConfigurationStoreContract {
+
+    Domain OTHER_DOMAIN = Domain.of("any.com");
+
+    @Test
+    default void listShouldReturnEmptyWhenNone(DLPConfigurationStore 
dlpConfigurationStore) {
+        assertThat(dlpConfigurationStore.list(Domain.LOCALHOST))
+            .isEmpty();
+    }
+
+    @Test
+    default void listShouldReturnExistingEntries(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE);
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE_2);
+
+        
assertThat(dlpConfigurationStore.list(Domain.LOCALHOST)).containsOnly(RULE_2);
+    }
+
+    @Test
+    default void 
listShouldNotReturnEntriesOfOtherDomains(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE);
+        dlpConfigurationStore.store(OTHER_DOMAIN, RULE_2);
+
+        
assertThat(dlpConfigurationStore.list(Domain.LOCALHOST)).containsOnly(RULE);
+    }
+
+    @Test
+    default void clearShouldRemoveAllEnriesOfADomain(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE);
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE_2);
+
+        dlpConfigurationStore.clear(Domain.LOCALHOST);
+
+        assertThat(dlpConfigurationStore.list(Domain.LOCALHOST)).isEmpty();
+    }
+
+    @Test
+    default void 
clearShouldNotFailWhenDomainDoesNotExist(DLPConfigurationStore 
dlpConfigurationStore) {
+        assertThatCode(() -> dlpConfigurationStore.clear(Domain.LOCALHOST))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void clearShouldOnlyRemoveEntriesOfADomain(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, RULE);
+        dlpConfigurationStore.store(OTHER_DOMAIN, RULE_2);
+
+        dlpConfigurationStore.clear(Domain.LOCALHOST);
+
+        
assertThat(dlpConfigurationStore.list(OTHER_DOMAIN)).containsOnly(RULE_2);
+    }
+    @Test
+    default void 
clearShouldOnlyRemovePreviouslyExistingEntries(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, ImmutableList.of(RULE, 
RULE_2));
+
+        dlpConfigurationStore.clear(Domain.LOCALHOST);
+
+        dlpConfigurationStore.store(Domain.LOCALHOST, ImmutableList.of(RULE));
+
+        
assertThat(dlpConfigurationStore.list(Domain.LOCALHOST)).containsOnly(RULE);
+    }
+
+    @Test
+    default void 
storeShouldOverwritePreviouslyStoredEntries(DLPConfigurationStore 
dlpConfigurationStore) {
+        dlpConfigurationStore.store(Domain.LOCALHOST, ImmutableList.of(RULE, 
RULE_2));
+        dlpConfigurationStore.store(Domain.LOCALHOST, ImmutableList.of(RULE));
+
+        
assertThat(dlpConfigurationStore.list(Domain.LOCALHOST)).containsOnly(RULE);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPFixture.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPFixture.java 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPFixture.java
new file mode 100644
index 0000000..9eea6fc
--- /dev/null
+++ 
b/server/data/data-api/src/test/java/org/apache/james/dlp/api/DLPFixture.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.dlp.api;
+
+public interface DLPFixture {
+    DLPConfigurationItem RULE = DLPConfigurationItem.builder()
+        .explanation("explanation")
+        .expression("regex")
+        .targetsSender()
+        .build();
+    DLPConfigurationItem RULE_2 = DLPConfigurationItem.builder()
+        .explanation("explanation2")
+        .expression("regex2")
+        .targetsSender()
+        .targetsRecipients()
+        .build();
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-library/pom.xml b/server/data/data-library/pom.xml
index fe9bb3e..1f3d16d 100644
--- a/server/data/data-library/pom.xml
+++ b/server/data/data-library/pom.xml
@@ -39,6 +39,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>event-sourcing-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-core</artifactId>
             <scope>test</scope>
         </dependency>
@@ -48,6 +52,12 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-data-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-dnsservice-api</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/EventSourcingDLPConfigurationStore.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/EventSourcingDLPConfigurationStore.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/EventSourcingDLPConfigurationStore.java
new file mode 100644
index 0000000..f367135
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/EventSourcingDLPConfigurationStore.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.dlp.eventsourcing;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.Domain;
+import org.apache.james.dlp.api.DLPConfigurationItem;
+import org.apache.james.dlp.api.DLPConfigurationStore;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPDomainConfiguration;
+import org.apache.james.dlp.eventsourcing.commands.ClearCommand;
+import org.apache.james.dlp.eventsourcing.commands.ClearCommandHandler;
+import org.apache.james.dlp.eventsourcing.commands.StoreCommand;
+import org.apache.james.dlp.eventsourcing.commands.StoreCommandHandler;
+import org.apache.james.eventsourcing.EventSourcingSystem;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+
+import com.google.common.collect.ImmutableSet;
+
+public class EventSourcingDLPConfigurationStore implements 
DLPConfigurationStore {
+
+    private static final ImmutableSet<Subscriber> NO_SUBSCRIBER = 
ImmutableSet.of();
+
+    private final EventSourcingSystem eventSourcingSystem;
+    private final EventStore eventStore;
+
+    @Inject
+    public EventSourcingDLPConfigurationStore(EventStore eventStore) {
+        this.eventSourcingSystem = new EventSourcingSystem(
+            ImmutableSet.of(
+                new ClearCommandHandler(eventStore),
+                new StoreCommandHandler(eventStore)),
+            NO_SUBSCRIBER,
+            eventStore);
+        this.eventStore = eventStore;
+    }
+
+    @Override
+    public Stream<DLPConfigurationItem> list(Domain domain) {
+
+        DLPAggregateId aggregateId = new DLPAggregateId(domain);
+
+        return DLPDomainConfiguration.load(
+                aggregateId,
+                eventStore.getEventsOfAggregate(aggregateId))
+            .retrieveRules();
+    }
+
+    @Override
+    public void store(Domain domain, List<DLPConfigurationItem> rules) {
+        eventSourcingSystem.dispatch(new StoreCommand(domain, rules));
+    }
+
+    @Override
+    public void clear(Domain domain) {
+        eventSourcingSystem.dispatch(new ClearCommand(domain));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateId.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateId.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateId.java
new file mode 100644
index 0000000..9e4a61b
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateId.java
@@ -0,0 +1,60 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.aggregates;
+
+import java.util.Objects;
+
+import org.apache.james.core.Domain;
+import org.apache.james.eventsourcing.AggregateId;
+
+import com.google.common.base.Preconditions;
+
+public class DLPAggregateId implements AggregateId {
+    private static final String SEPARATOR = "/";
+    private static final String PREFIX = "DLPRule";
+
+    private final Domain domain;
+
+    public DLPAggregateId(Domain domain) {
+        Preconditions.checkNotNull(domain);
+
+        this.domain = domain;
+    }
+
+    @Override
+    public String asAggregateKey() {
+        return PREFIX + SEPARATOR + domain.asString();
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof DLPAggregateId) {
+            DLPAggregateId that = (DLPAggregateId) o;
+
+            return Objects.equals(this.domain, that.domain);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(domain);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPDomainConfiguration.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPDomainConfiguration.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPDomainConfiguration.java
new file mode 100644
index 0000000..ece6353
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/aggregates/DLPDomainConfiguration.java
@@ -0,0 +1,151 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.dlp.eventsourcing.aggregates;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.james.dlp.api.DLPConfigurationItem;
+import org.apache.james.dlp.eventsourcing.events.ConfigurationItemsAdded;
+import org.apache.james.dlp.eventsourcing.events.ConfigurationItemsRemoved;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.eventsourcing.eventstore.History;
+import org.apache.james.util.OptionalUtils;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+public class DLPDomainConfiguration {
+
+    public static DLPDomainConfiguration load(DLPAggregateId aggregateId, 
History history) {
+        return new DLPDomainConfiguration(aggregateId, history);
+    }
+
+    private static class State {
+
+        static State initial() {
+            return new State(ImmutableSet.of());
+        }
+
+        final ImmutableSet<DLPConfigurationItem> rules;
+
+        private State(ImmutableSet<DLPConfigurationItem> rules) {
+            this.rules = rules;
+        }
+
+        State add(DLPConfigurationItem rule) {
+            return add(ImmutableList.of(rule));
+        }
+
+        State add(List<DLPConfigurationItem> toAdd) {
+            ImmutableSet<DLPConfigurationItem> union = 
Stream.concat(this.rules.stream(), 
toAdd.stream()).collect(Guavate.toImmutableSet());
+            return new State(union);
+        }
+
+        State remove(DLPConfigurationItem toRemove) {
+            return remove(ImmutableList.of(toRemove));
+        }
+
+        State remove(List<DLPConfigurationItem> toRemove) {
+            ImmutableSet<DLPConfigurationItem> filtered = 
rules.stream().filter(rule -> 
!toRemove.contains(rule)).collect(Guavate.toImmutableSet());
+            return new State(filtered);
+        }
+    }
+
+    private final DLPAggregateId aggregateId;
+    private final History history;
+    private State state;
+
+    private DLPDomainConfiguration(DLPAggregateId aggregateId, History 
history) {
+        this.aggregateId = aggregateId;
+        this.state = State.initial();
+        history.getEvents().forEach(this::apply);
+        this.history = history;
+    }
+
+    public Stream<DLPConfigurationItem> retrieveRules() {
+        return state.rules.stream();
+    }
+
+    public List<Event> clear() {
+        ImmutableList<DLPConfigurationItem> rules = 
retrieveRules().collect(Guavate.toImmutableList());
+        if (!rules.isEmpty()) {
+            ImmutableList<Event> events = ImmutableList.of(new 
ConfigurationItemsRemoved(aggregateId, history.getNextEventId(), rules));
+            events.forEach(this::apply);
+            return events;
+        } else {
+            return ImmutableList.of();
+        }
+    }
+
+    public List<Event> store(List<DLPConfigurationItem> updatedRules) {
+        ImmutableSet<DLPConfigurationItem> existingRules = 
retrieveRules().collect(Guavate.toImmutableSet());
+        ImmutableSet<DLPConfigurationItem> updatedRulesSet = 
ImmutableSet.copyOf(updatedRules);
+
+        Optional<Event> removedRulesEvent = 
generateRemovedRulesEvent(existingRules, updatedRulesSet);
+        Optional<Event> addedRulesEvent = 
generateAddedRulesEvent(existingRules, updatedRulesSet, 
computeNextEventId(removedRulesEvent));
+
+        ImmutableList<Event> events = Stream
+            .of(removedRulesEvent, addedRulesEvent)
+            .flatMap(OptionalUtils::toStream)
+            .collect(Guavate.toImmutableList());
+
+        events.forEach(this::apply);
+        return events;
+    }
+
+    private EventId computeNextEventId(Optional<Event> removedRulesEvent) {
+        return removedRulesEvent
+            .map(Event::eventId)
+            .map(EventId::next)
+            .orElse(history.getNextEventId());
+    }
+
+    private Optional<Event> 
generateRemovedRulesEvent(ImmutableSet<DLPConfigurationItem> existingRules, 
ImmutableSet<DLPConfigurationItem> updateRulesSet) {
+        Set<DLPConfigurationItem> removedRules = 
Sets.difference(existingRules, updateRulesSet);
+        if (!removedRules.isEmpty()) {
+            return Optional.of(new ConfigurationItemsRemoved(aggregateId, 
history.getNextEventId(), removedRules));
+        }
+        return Optional.empty();
+    }
+
+    private Optional<Event> generateAddedRulesEvent(Set<DLPConfigurationItem> 
existingRules, Set<DLPConfigurationItem> updateRulesSet, EventId nextEventId) {
+        Set<DLPConfigurationItem> addedRules = Sets.difference(updateRulesSet, 
existingRules);
+        if (!addedRules.isEmpty()) {
+            return Optional.of(new ConfigurationItemsAdded(aggregateId, 
nextEventId, addedRules));
+        }
+        return Optional.empty();
+    }
+
+    private void apply(Event event) {
+        if (event instanceof ConfigurationItemsAdded) {
+            state = state.add(((ConfigurationItemsAdded) event).getRules());
+        }
+        if (event instanceof ConfigurationItemsRemoved) {
+            state = state.remove(((ConfigurationItemsRemoved) 
event).getRules());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommand.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommand.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommand.java
new file mode 100644
index 0000000..1cb4513
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommand.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.commands;
+
+import java.util.Objects;
+
+import org.apache.james.core.Domain;
+import org.apache.james.eventsourcing.Command;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class ClearCommand implements Command {
+    private final Domain domain;
+
+    public ClearCommand(Domain domain) {
+        Preconditions.checkNotNull(domain);
+
+        this.domain = domain;
+    }
+
+    public Domain getDomain() {
+        return domain;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ClearCommand) {
+            ClearCommand that = (ClearCommand) o;
+
+            return Objects.equals(this.domain, that.domain);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(domain);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("domain", domain)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandHandler.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandHandler.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandHandler.java
new file mode 100644
index 0000000..a0b0c18
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandHandler.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.dlp.eventsourcing.commands;
+
+import java.util.List;
+
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPDomainConfiguration;
+import org.apache.james.eventsourcing.CommandHandler;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+
+public class ClearCommandHandler implements CommandHandler<ClearCommand> {
+
+    private final EventStore eventStore;
+
+    public ClearCommandHandler(EventStore eventStore) {
+        this.eventStore = eventStore;
+    }
+
+    @Override
+    public Class<ClearCommand> handledClass() {
+        return ClearCommand.class;
+    }
+
+    @Override
+    public List<? extends Event> handle(ClearCommand clearCommand) {
+        DLPAggregateId aggregateId = new 
DLPAggregateId(clearCommand.getDomain());
+
+        return DLPDomainConfiguration.load(
+                aggregateId,
+                eventStore.getEventsOfAggregate(aggregateId))
+            .clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommand.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommand.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommand.java
new file mode 100644
index 0000000..d48bfa4
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommand.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.commands;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.james.core.Domain;
+import org.apache.james.dlp.api.DLPConfigurationItem;
+import org.apache.james.eventsourcing.Command;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class StoreCommand implements Command {
+    private final Domain domain;
+    private final List<DLPConfigurationItem> rules;
+
+    public StoreCommand(Domain domain, List<DLPConfigurationItem> rules) {
+        Preconditions.checkNotNull(domain);
+        Preconditions.checkNotNull(rules);
+
+        this.domain = domain;
+        this.rules = rules;
+    }
+
+    public Domain getDomain() {
+        return domain;
+    }
+
+    public List<DLPConfigurationItem> getRules() {
+        return rules;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof StoreCommand) {
+            StoreCommand that = (StoreCommand) o;
+
+            return Objects.equals(this.domain, that.domain)
+                && Objects.equals(this.rules, that.rules);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(domain, rules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("domain", domain)
+            .add("rules", rules)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandHandler.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandHandler.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandHandler.java
new file mode 100644
index 0000000..dc81548
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandHandler.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.dlp.eventsourcing.commands;
+
+import java.util.List;
+
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPDomainConfiguration;
+import org.apache.james.eventsourcing.CommandHandler;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+
+public class StoreCommandHandler implements CommandHandler<StoreCommand> {
+
+    private final EventStore eventStore;
+
+    public StoreCommandHandler(EventStore eventStore) {
+        this.eventStore = eventStore;
+    }
+
+    @Override
+    public Class<StoreCommand> handledClass() {
+        return StoreCommand.class;
+    }
+
+    @Override
+    public List<? extends Event> handle(StoreCommand storeCommand) {
+        DLPAggregateId aggregateId = new 
DLPAggregateId(storeCommand.getDomain());
+
+        return DLPDomainConfiguration.load(
+                aggregateId,
+                eventStore.getEventsOfAggregate(aggregateId))
+            .store(storeCommand.getRules());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAdded.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAdded.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAdded.java
new file mode 100644
index 0000000..7a150df
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAdded.java
@@ -0,0 +1,89 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.events;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.james.dlp.api.DLPConfigurationItem;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+public class ConfigurationItemsAdded implements Event {
+    private final DLPAggregateId aggregateId;
+    private final EventId eventId;
+    private final List<DLPConfigurationItem> rules;
+
+    public ConfigurationItemsAdded(DLPAggregateId aggregateId, EventId 
eventId, Collection<DLPConfigurationItem> rules) {
+        Preconditions.checkNotNull(aggregateId);
+        Preconditions.checkNotNull(eventId);
+        Preconditions.checkNotNull(rules);
+        Preconditions.checkArgument(!rules.isEmpty());
+
+        this.aggregateId = aggregateId;
+        this.eventId = eventId;
+        this.rules = ImmutableList.copyOf(rules);
+    }
+
+    @Override
+    public EventId eventId() {
+        return eventId;
+    }
+
+    public DLPAggregateId getAggregateId() {
+        return aggregateId;
+    }
+
+    public List<DLPConfigurationItem> getRules() {
+        return rules;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ConfigurationItemsAdded) {
+            ConfigurationItemsAdded that = (ConfigurationItemsAdded) o;
+
+            return Objects.equals(this.aggregateId, that.aggregateId)
+                && Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.rules, that.rules);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(aggregateId, eventId, rules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("aggregateId", aggregateId)
+            .add("eventId", eventId)
+            .add("rules", rules)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemoved.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemoved.java
 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemoved.java
new file mode 100644
index 0000000..572617a
--- /dev/null
+++ 
b/server/data/data-library/src/main/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemoved.java
@@ -0,0 +1,91 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.events;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.james.dlp.api.DLPConfigurationItem;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+public class ConfigurationItemsRemoved implements Event {
+    private final DLPAggregateId aggregateId;
+    private final EventId eventId;
+    private final List<DLPConfigurationItem> rules;
+
+    public ConfigurationItemsRemoved(DLPAggregateId aggregateId, EventId 
eventId, Collection<DLPConfigurationItem> rules) {
+        Preconditions.checkNotNull(aggregateId);
+        Preconditions.checkNotNull(eventId);
+        Preconditions.checkNotNull(rules);
+        Preconditions.checkArgument(!rules.isEmpty());
+
+        this.aggregateId = aggregateId;
+        this.eventId = eventId;
+        this.rules = ImmutableList.copyOf(rules);
+    }
+
+    @Override
+    public EventId eventId() {
+        return eventId;
+    }
+
+    @Override
+    public AggregateId getAggregateId() {
+        return aggregateId;
+    }
+
+    public List<DLPConfigurationItem> getRules() {
+        return rules;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ConfigurationItemsRemoved) {
+            ConfigurationItemsRemoved that = (ConfigurationItemsRemoved) o;
+
+            return Objects.equals(this.aggregateId, that.aggregateId)
+                && Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.rules, that.rules);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(aggregateId, eventId, rules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("aggregateId", aggregateId)
+            .add("eventId", eventId)
+            .add("rules", rules)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateIdTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateIdTest.java
 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateIdTest.java
new file mode 100644
index 0000000..3604974
--- /dev/null
+++ 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/aggregates/DLPAggregateIdTest.java
@@ -0,0 +1,51 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.aggregates;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.Domain;
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class DLPAggregateIdTest {
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(DLPAggregateId.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullDomain() {
+        assertThatThrownBy(() -> new DLPAggregateId(null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void 
asAggregateKeyShouldReturnAStringContainingThePrefixAndTheDomain() {
+        assertThat(new DLPAggregateId(Domain.LOCALHOST).asAggregateKey())
+            .isEqualTo("DLPRule/localhost");
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandTest.java
 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandTest.java
new file mode 100644
index 0000000..d859728
--- /dev/null
+++ 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/ClearCommandTest.java
@@ -0,0 +1,43 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.commands;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class ClearCommandTest {
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(ClearCommand.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullDomain() {
+        assertThatThrownBy(() -> new ClearCommand(null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandTest.java
 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandTest.java
new file mode 100644
index 0000000..5b6b473
--- /dev/null
+++ 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/commands/StoreCommandTest.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.commands;
+
+import static org.apache.james.dlp.api.DLPFixture.RULE;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.Domain;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class StoreCommandTest {
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(StoreCommand.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullDomain() {
+        assertThatThrownBy(() -> new StoreCommand(null, 
ImmutableList.of(RULE)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullRules() {
+        assertThatThrownBy(() -> new StoreCommand(Domain.LOCALHOST, null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAddedTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAddedTest.java
 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAddedTest.java
new file mode 100644
index 0000000..3aa81b5
--- /dev/null
+++ 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsAddedTest.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.events;
+
+import static org.apache.james.dlp.api.DLPFixture.RULE;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.Domain;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.eventsourcing.EventId;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class ConfigurationItemsAddedTest {
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(ConfigurationItemsAdded.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullAggregateId() {
+        assertThatThrownBy(() -> new ConfigurationItemsAdded(null, 
EventId.first(), ImmutableList.of(RULE)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullEventId() {
+        assertThatThrownBy(() -> new ConfigurationItemsAdded(new 
DLPAggregateId(Domain.LOCALHOST), null, ImmutableList.of(RULE)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullRules() {
+        assertThatThrownBy(() -> new ConfigurationItemsAdded(new 
DLPAggregateId(Domain.LOCALHOST), EventId.first(), null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenEmptyRulesList() {
+        assertThatThrownBy(() -> new ConfigurationItemsAdded(new 
DLPAggregateId(Domain.LOCALHOST), EventId.first(), ImmutableList.of()))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemovedTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemovedTest.java
 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemovedTest.java
new file mode 100644
index 0000000..2a2027b
--- /dev/null
+++ 
b/server/data/data-library/src/test/java/org/apache/james/dlp/eventsourcing/events/ConfigurationItemsRemovedTest.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.dlp.eventsourcing.events;
+
+import static org.apache.james.dlp.api.DLPFixture.RULE;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.Domain;
+import org.apache.james.dlp.eventsourcing.aggregates.DLPAggregateId;
+import org.apache.james.eventsourcing.EventId;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class ConfigurationItemsRemovedTest {
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(ConfigurationItemsRemoved.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullAggregateId() {
+        assertThatThrownBy(() -> new ConfigurationItemsRemoved(null, 
EventId.first(), ImmutableList.of(RULE)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullEventId() {
+        assertThatThrownBy(() -> new ConfigurationItemsRemoved(new 
DLPAggregateId(Domain.LOCALHOST), null, ImmutableList.of()))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenEmptyRulesList() {
+        assertThatThrownBy(() -> new ConfigurationItemsRemoved(new 
DLPAggregateId(Domain.LOCALHOST), EventId.first(), ImmutableList.of()))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void constructorShouldThrowWhenNullRulesList() {
+        assertThatThrownBy(() -> new ConfigurationItemsRemoved(new 
DLPAggregateId(Domain.LOCALHOST), EventId.first(), null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-memory/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-memory/pom.xml b/server/data/data-memory/pom.xml
index 6b4661b..38c543b 100644
--- a/server/data/data-memory/pom.xml
+++ b/server/data/data-memory/pom.xml
@@ -35,7 +35,18 @@
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>event-sourcing-event-store-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-data-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/EventSourcingDLPConfigurationStoreTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/EventSourcingDLPConfigurationStoreTest.java
 
b/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/EventSourcingDLPConfigurationStoreTest.java
new file mode 100644
index 0000000..a226fce
--- /dev/null
+++ 
b/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/EventSourcingDLPConfigurationStoreTest.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.dlp.memory;
+
+import org.apache.james.dlp.api.DLPConfigurationStoreContract;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(InMemoryEventSourcingDLPConfigurationStoreExtension.class)
+public class EventSourcingDLPConfigurationStoreTest implements 
DLPConfigurationStoreContract {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f368fc7/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/InMemoryEventSourcingDLPConfigurationStoreExtension.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/InMemoryEventSourcingDLPConfigurationStoreExtension.java
 
b/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/InMemoryEventSourcingDLPConfigurationStoreExtension.java
new file mode 100644
index 0000000..fe9392c
--- /dev/null
+++ 
b/server/data/data-memory/src/test/java/org/apache/james/dlp/memory/InMemoryEventSourcingDLPConfigurationStoreExtension.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.dlp.memory;
+
+import org.apache.james.dlp.api.DLPConfigurationStore;
+import org.apache.james.dlp.eventsourcing.EventSourcingDLPConfigurationStore;
+import org.apache.james.eventsourcing.eventstore.memory.InMemoryEventStore;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+public class InMemoryEventSourcingDLPConfigurationStoreExtension implements 
ParameterResolver {
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType() == 
DLPConfigurationStore.class);
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext) throws ParameterResolutionException {
+        return new EventSourcingDLPConfigurationStore(new 
InMemoryEventStore());
+    }
+}


---------------------------------------------------------------------
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