You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ad...@apache.org on 2018/08/23 12:50:05 UTC
[4/8] james-project git commit: JAMES-2528 implementation of a
FilteringManagement API using Event Sourcing
JAMES-2528 implementation of a FilteringManagement API using Event Sourcing
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/58f0f800
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/58f0f800
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/58f0f800
Branch: refs/heads/master
Commit: 58f0f800632189fda5fd1a4b9d5cfd89e991f2c4
Parents: d125ba9
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Aug 22 16:08:23 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Thu Aug 23 14:29:33 2018 +0200
----------------------------------------------------------------------
server/data/data-jmap/pom.xml | 23 ++++-
.../jmap/api/filtering/FilteringManagement.java | 32 +++++++
.../apache/james/jmap/api/filtering/Rule.java | 67 +++++++++++++
.../api/filtering/impl/DefineRulesCommand.java | 76 +++++++++++++++
.../impl/DefineRulesCommandHandler.java | 52 +++++++++++
.../impl/EventSourcingFilteringManagement.java | 69 ++++++++++++++
.../api/filtering/impl/FilteringAggregate.java | 90 ++++++++++++++++++
.../filtering/impl/FilteringAggregateId.java | 73 +++++++++++++++
.../jmap/api/filtering/impl/RuleSetDefined.java | 85 +++++++++++++++++
.../api/filtering/FilteringAggregateIdTest.java | 86 +++++++++++++++++
.../filtering/FilteringManagementContract.java | 98 ++++++++++++++++++++
.../james/jmap/api/filtering/RuleTest.java | 41 ++++++++
.../filtering/impl/DefineRulesCommandTest.java | 51 ++++++++++
.../EventSourcingFilteringManagementTest.java | 32 +++++++
14 files changed, 873 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/pom.xml b/server/data/data-jmap/pom.xml
index 7c7f049..169120b 100644
--- a/server/data/data-jmap/pom.xml
+++ b/server/data/data-jmap/pom.xml
@@ -42,6 +42,15 @@
<artifactId>james-server-util</artifactId>
</dependency>
<dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>event-sourcing-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>event-sourcing-event-store-memory</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
@@ -55,8 +64,8 @@
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
+ <groupId>nl.jqno.equalsverifier</groupId>
+ <artifactId>equalsverifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
@@ -74,6 +83,16 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/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
new file mode 100644
index 0000000..a8b1c4b
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.api.filtering;
+
+import java.util.List;
+
+import org.apache.james.core.User;
+
+public interface FilteringManagement {
+
+ void defineRulesForUser(User user, List<Rule> rules);
+
+ List<Rule> listRulesForUser(User user);
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/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
new file mode 100644
index 0000000..8bca30a
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.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.jmap.api.filtering;
+
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class Rule {
+
+ private final String id;
+
+ public static Rule of(String id) {
+ return new Rule(id);
+ }
+
+ public Rule(String id) {
+ Preconditions.checkNotNull(id);
+
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof Rule) {
+ Rule rule = (Rule) o;
+
+ return Objects.equals(this.id, rule.id);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("id", id)
+ .toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
new file mode 100644
index 0000000..0cd256c
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * 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.impl;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class DefineRulesCommand implements Command {
+
+ private final User user;
+ private final List<Rule> rules;
+
+ public DefineRulesCommand(User user, List<Rule> rules) {
+ Preconditions.checkNotNull(user);
+ Preconditions.checkNotNull(rules);
+
+ this.user = user;
+ this.rules = rules;
+ }
+
+ public List<Rule> getRules() {
+ return rules;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof DefineRulesCommand) {
+ DefineRulesCommand that = (DefineRulesCommand) o;
+
+ return Objects.equals(this.user, that.user)
+ && Objects.equals(this.rules, that.rules);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(user, rules);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("user", user)
+ .add("rules", rules)
+ .toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java
new file mode 100644
index 0000000..a613893
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.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.jmap.api.filtering.impl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.CommandHandler;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+
+public class DefineRulesCommandHandler implements CommandHandler<DefineRulesCommand> {
+
+ private final EventStore eventStore;
+
+ public DefineRulesCommandHandler(EventStore eventStore) {
+ this.eventStore = eventStore;
+ }
+
+ @Override
+ public Class<DefineRulesCommand> handledClass() {
+ return DefineRulesCommand.class;
+ }
+
+ @Override
+ public List<? extends Event> handle(DefineRulesCommand storeCommand) {
+ FilteringAggregateId aggregateId = new FilteringAggregateId(storeCommand.getUser());
+
+ return FilteringAggregate
+ .load(
+ aggregateId,
+ eventStore.getEventsOfAggregate(aggregateId))
+ .defineRules(storeCommand.getRules());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
new file mode 100644
index 0000000..2fbba65
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
@@ -0,0 +1,69 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.api.filtering.impl;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.EventSourcingSystem;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
+public class EventSourcingFilteringManagement implements FilteringManagement {
+
+ private static final ImmutableSet<Subscriber> NO_SUBSCRIBER = ImmutableSet.of();
+
+ private final EventStore eventStore;
+ private final EventSourcingSystem eventSourcingSystem;
+
+ @Inject
+ public EventSourcingFilteringManagement(EventStore eventStore) {
+ this.eventSourcingSystem = new EventSourcingSystem(
+ ImmutableSet.of(new DefineRulesCommandHandler(eventStore)),
+ NO_SUBSCRIBER,
+ eventStore);
+ this.eventStore = eventStore;
+ }
+
+ @Override
+ public void defineRulesForUser(User user, List<Rule> rules) {
+ eventSourcingSystem.dispatch(new DefineRulesCommand(user, rules));
+ }
+
+ @Override
+ public List<Rule> listRulesForUser(User user) {
+ Preconditions.checkNotNull(user);
+
+ FilteringAggregateId aggregateId = new FilteringAggregateId(user);
+
+ return FilteringAggregate
+ .load(
+ aggregateId,
+ eventStore.getEventsOfAggregate(aggregateId))
+ .listRules();
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
new file mode 100644
index 0000000..33970f2
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
@@ -0,0 +1,90 @@
+/****************************************************************
+ * 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.impl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.History;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+public class FilteringAggregate {
+
+ public static FilteringAggregate load(FilteringAggregateId aggregateId, History eventsOfAggregate) {
+ return new FilteringAggregate(aggregateId, eventsOfAggregate);
+ }
+
+ private static class State {
+
+ static State initial() {
+ return new State(ImmutableList.of());
+ }
+
+ final ImmutableList<Rule> rules;
+
+ private State(ImmutableList<Rule> rules) {
+ this.rules = rules;
+ }
+
+ State set(ImmutableList<Rule> rules) {
+ return new State(rules);
+ }
+ }
+
+ private final FilteringAggregateId aggregateId;
+ private final History history;
+ private State state;
+
+ private FilteringAggregate(FilteringAggregateId aggregateId, History history) {
+ this.aggregateId = aggregateId;
+ this.state = State.initial();
+ history.getEvents().forEach(this::apply);
+ this.history = history;
+ }
+
+ public List<? extends Event> defineRules(List<Rule> rules) {
+ Preconditions.checkArgument(shouldNotContainDuplicates(rules));
+ ImmutableList<RuleSetDefined> events = ImmutableList.of(
+ new RuleSetDefined(aggregateId, history.getNextEventId(), ImmutableList.copyOf(rules)));
+ events.forEach(this::apply);
+ return events;
+ }
+
+ private boolean shouldNotContainDuplicates(List<Rule> rules) {
+ long uniqueIdCount = rules.stream()
+ .map(Rule::getId)
+ .distinct()
+ .count();
+ return uniqueIdCount == rules.size();
+ }
+
+ public List<Rule> listRules() {
+ return state.rules;
+ }
+
+ private void apply(Event event) {
+ if (event instanceof RuleSetDefined) {
+ state = state.set(((RuleSetDefined)event).getRules());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
new file mode 100644
index 0000000..635f045
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * 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.impl;
+
+import java.util.Objects;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.AggregateId;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class FilteringAggregateId implements AggregateId {
+ private static final String SEPARATOR = "/";
+ private static final String PREFIX = "FilteringRule";
+
+ public static final FilteringAggregateId parse(String rawString) {
+ Preconditions.checkArgument(rawString.startsWith(PREFIX + SEPARATOR));
+ return new FilteringAggregateId(User.fromUsername(rawString.substring(PREFIX.length() + SEPARATOR.length())));
+ }
+
+ private final User user;
+
+ public FilteringAggregateId(User user) {
+ Preconditions.checkNotNull(user);
+
+ this.user = user;
+ }
+
+ @Override
+ public String asAggregateKey() {
+ return PREFIX + SEPARATOR + user.asString();
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof FilteringAggregateId) {
+ FilteringAggregateId that = (FilteringAggregateId) o;
+
+ return Objects.equals(this.user, that.user);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(user);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("user", user)
+ .toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
new file mode 100644
index 0000000..dacba35
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * 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.impl;
+
+import java.util.Objects;
+
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+
+public class RuleSetDefined implements Event {
+
+ private final FilteringAggregateId aggregateId;
+ private final EventId eventId;
+ private final ImmutableList<Rule> rules;
+
+ RuleSetDefined(FilteringAggregateId aggregateId, EventId eventId, ImmutableList<Rule> rules) {
+ this.aggregateId = aggregateId;
+ this.eventId = eventId;
+ this.rules = rules;
+ }
+
+ @Override
+ public EventId eventId() {
+ return eventId;
+ }
+
+ @Override
+ public AggregateId getAggregateId() {
+ return aggregateId;
+ }
+
+ public ImmutableList<Rule> getRules() {
+ return rules;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RuleSetDefined that = (RuleSetDefined) o;
+ return Objects.equals(aggregateId, that.aggregateId) &&
+ Objects.equals(eventId, that.eventId) &&
+ Objects.equals(rules, that.rules);
+ }
+
+ @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/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
new file mode 100644
index 0000000..8588938
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
@@ -0,0 +1,86 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+
+import org.apache.james.jmap.api.filtering.impl.FilteringAggregateId;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class FilteringAggregateIdTest {
+
+ @Test
+ void shouldMatchBeanContract() {
+ EqualsVerifier.forClass(FilteringAggregateId.class).verify();
+ }
+
+ @Test
+ void constructorShouldThrowWhenNullDomain() {
+ assertThatThrownBy(() -> new FilteringAggregateId(null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ void asAggregateKeyShouldReturnAStringContainingThePrefixAndTheDomain() {
+ assertThat(new FilteringAggregateId(User.fromUsername("foo@bar.space")).asAggregateKey())
+ .isEqualTo("FilteringRule/foo@bar.space");
+ }
+
+ @Test
+ void parseShouldThrowWhenNullString() {
+ assertThatThrownBy(() -> FilteringAggregateId.parse(null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ void parseShouldThrowWhenStringDoesntMatchPrefix() {
+ assertThatThrownBy(() -> FilteringAggregateId.parse("WrongPrefix/foo"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseShouldThrowWhenStringDoesntContainSeparator() {
+ assertThatThrownBy(() -> FilteringAggregateId.parse("WrongPrefix"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseShouldThrowWhenStringDoesntContainUser() {
+ assertThatThrownBy(() -> FilteringAggregateId.parse("FilteringRule/"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseShouldThrowWhenStringDoesntHavePrefix() {
+ assertThatThrownBy(() -> FilteringAggregateId.parse("FilteringRulefoo"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseShouldKeepSlashInUsername() {
+ assertThat(FilteringAggregateId.parse("FilteringRule/f/oo@bar.space").asAggregateKey())
+ .isEqualTo("FilteringRule/f/oo@bar.space");
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/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
new file mode 100644
index 0000000..98683b8
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
@@ -0,0 +1,98 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+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");
+
+ FilteringManagement instanciateFilteringManagement();
+
+ @Test
+ default void listingRulesForUnknownUserShouldReturnEmptyList() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ assertThat(instanciateFilteringManagement().listRulesForUser(user)).isEmpty();
+ }
+
+ @Test
+ default void listingRulesShouldThrowWhenNullUser() {
+ User user = null;
+ assertThatThrownBy(() -> instanciateFilteringManagement().listRulesForUser(user)).isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ default void listingRulesShouldReturnDefinedRules() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ FilteringManagement testee = instanciateFilteringManagement();
+ testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2));
+ assertThat(testee.listRulesForUser(user)).containsExactly(RULE_1, RULE_2);
+ }
+
+ @Test
+ default void listingRulesShouldReturnLastDefinedRules() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ FilteringManagement testee = instanciateFilteringManagement();
+ 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);
+ }
+
+ @Test
+ default void definingRulesShouldThrowWhenDuplicateRules() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ FilteringManagement testee = instanciateFilteringManagement();
+ assertThatThrownBy(() -> testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_1)))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ default void definingRulesShouldThrowWhenNullUser() {
+ FilteringManagement testee = instanciateFilteringManagement();
+ assertThatThrownBy(() -> testee.defineRulesForUser(null, ImmutableList.of(RULE_1, RULE_1)))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ default void definingRulesShouldThrowWhenNullRuleList() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ FilteringManagement testee = instanciateFilteringManagement();
+ assertThatThrownBy(() -> testee.defineRulesForUser(user, null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ default void definingRulesShouldKeepOrdering() {
+ User user = User.fromUsername(BART_SIMPSON_CARTOON);
+ FilteringManagement testee = instanciateFilteringManagement();
+ testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, RULE_1));
+ assertThat(testee.listRulesForUser(user)).containsExactly(RULE_3, RULE_2, RULE_1);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/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
new file mode 100644
index 0000000..fc10f6a
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.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.jmap.api.filtering;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class RuleTest {
+
+ @Test
+ void shouldMatchBeanContract() {
+ EqualsVerifier.forClass(Rule.class)
+ .verify();
+ }
+
+ @Test
+ void constructorShouldThrowWhenNullId() {
+ assertThatThrownBy(() -> new Rule(null))
+ .isInstanceOf(NullPointerException.class);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/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
new file mode 100644
index 0000000..a917fdd
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.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.jmap.api.filtering.impl;
+
+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;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class DefineRulesCommandTest {
+
+ @Test
+ void shouldMatchBeanContract() {
+ EqualsVerifier.forClass(DefineRulesCommand.class)
+ .verify();
+ }
+
+ @Test
+ void constructorShouldThrowWhenNullUser() {
+ assertThatThrownBy(() -> new DefineRulesCommand(null, ImmutableList.of(Rule.of("1"), Rule.of("2"))))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ void constructorShouldThrowWhenNullRuleList() {
+ assertThatThrownBy(() -> new DefineRulesCommand(User.fromUsername("adam@james.org"), null))
+ .isInstanceOf(NullPointerException.class);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
new file mode 100644
index 0000000..45120c3
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.api.filtering.impl;
+
+import org.apache.james.eventsourcing.eventstore.memory.InMemoryEventStore;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.FilteringManagementContract;
+
+public class EventSourcingFilteringManagementTest implements FilteringManagementContract {
+
+ @Override
+ public FilteringManagement instanciateFilteringManagement() {
+ return new EventSourcingFilteringManagement(new InMemoryEventStore());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org