You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/08/03 02:01:18 UTC
[james-project] branch master updated: JAMES-3516 Implement Thread
Cassandra table
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 33bbc51 JAMES-3516 Implement Thread Cassandra table
33bbc51 is described below
commit 33bbc51f44733e8c7f14ae88f2cd172028b7dd2b
Author: quanth <hq...@linagora.com>
AuthorDate: Thu Jul 22 17:48:39 2021 +0700
JAMES-3516 Implement Thread Cassandra table
---
.../mailbox/cassandra/mail/CassandraThreadDAO.java | 114 +++++++++++++
.../cassandra/modules/CassandraThreadModule.java | 45 +++++
.../cassandra/table/CassandraThreadTable.java | 35 ++++
.../cassandra/mail/CassandraThreadDAOTest.java | 190 +++++++++++++++++++++
.../modules/mailbox/CassandraMailboxModule.java | 1 +
.../mailbox/CassandraThreadIdGuessingModule.java | 39 +++++
6 files changed, 424 insertions(+)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
new file mode 100644
index 0000000..b474553
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
@@ -0,0 +1,114 @@
+/******************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ******************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.THREAD_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MESSAGE_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.BASE_SUBJECT;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.MIME_MESSAGE_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.TABLE_NAME;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.USERNAME;
+import static org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY;
+
+import java.util.Optional;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
+import org.apache.james.mailbox.store.mail.model.MimeMessageId;
+import org.apache.james.mailbox.store.mail.model.Subject;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+
+import reactor.core.publisher.Flux;
+
+public class CassandraThreadDAO {
+ private final CassandraAsyncExecutor executor;
+ private final PreparedStatement insertOne;
+ private final PreparedStatement selectOne;
+ private final PreparedStatement deleteOne;
+
+ @Inject
+ public CassandraThreadDAO(Session session) {
+ executor = new CassandraAsyncExecutor(session);
+
+ insertOne = session.prepare(insertInto(TABLE_NAME)
+ .value(USERNAME, bindMarker(USERNAME))
+ .value(MIME_MESSAGE_ID, bindMarker(MIME_MESSAGE_ID))
+ .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
+ .value(THREAD_ID, bindMarker(THREAD_ID))
+ .value(BASE_SUBJECT, bindMarker(BASE_SUBJECT)));
+
+ selectOne = session.prepare(select(BASE_SUBJECT, THREAD_ID)
+ .from(TABLE_NAME)
+ .where(eq(USERNAME, bindMarker(USERNAME)))
+ .and(eq(MIME_MESSAGE_ID, bindMarker(MIME_MESSAGE_ID))));
+
+ deleteOne = session.prepare(delete().from(TABLE_NAME)
+ .where(eq(USERNAME, bindMarker(USERNAME)))
+ .and(eq(MIME_MESSAGE_ID, bindMarker(MIME_MESSAGE_ID))));
+ }
+
+ public Flux<Void> insertSome(Username username, Set<MimeMessageId> mimeMessageIds, MessageId messageId, ThreadId threadId, Optional<Subject> baseSubject) {
+ return Flux.fromIterable(mimeMessageIds)
+ .flatMap(mimeMessageId -> executor.executeVoid(insertOne.bind()
+ .setString(USERNAME, username.asString())
+ .setString(MIME_MESSAGE_ID, mimeMessageId.getValue())
+ .setUUID(MESSAGE_ID, ((CassandraMessageId) messageId).get())
+ .setUUID(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get())
+ .setString(BASE_SUBJECT, baseSubject.map(Subject::getValue).orElse(null))), DEFAULT_CONCURRENCY);
+ }
+
+ public Flux<Pair<Optional<Subject>, ThreadId>> selectSome(Username username, Set<MimeMessageId> mimeMessageIds) {
+ return Flux.fromIterable(mimeMessageIds)
+ .flatMap(mimeMessageId -> executor
+ .executeSingleRow(selectOne.bind()
+ .setString(USERNAME, username.asString())
+ .setString(MIME_MESSAGE_ID, mimeMessageId.getValue()))
+ .map(this::readRow), DEFAULT_CONCURRENCY)
+ .distinct();
+ }
+
+ public Flux<Void> deleteSome(Username username, Set<MimeMessageId> mimeMessageIds) {
+ return Flux.fromIterable(mimeMessageIds)
+ .flatMap(mimeMessageId -> executor.executeVoid(deleteOne.bind()
+ .setString(USERNAME, username.asString())
+ .setString(MIME_MESSAGE_ID, mimeMessageId.getValue())));
+ }
+
+ public Pair<Optional<Subject>, ThreadId> readRow(Row row) {
+ return Pair.of(Optional.ofNullable(row.getString(BASE_SUBJECT)).map(Subject::new),
+ ThreadId.fromBaseMessageId(CassandraMessageId.Factory.of(row.getUUID(THREAD_ID))));
+ }
+
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraThreadModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraThreadModule.java
new file mode 100644
index 0000000..f75bec3
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraThreadModule.java
@@ -0,0 +1,45 @@
+/******************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ******************************************************************/
+
+package org.apache.james.mailbox.cassandra.modules;
+
+import static com.datastax.driver.core.DataType.text;
+import static com.datastax.driver.core.DataType.timeuuid;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.THREAD_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MESSAGE_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.BASE_SUBJECT;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.MIME_MESSAGE_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.TABLE_NAME;
+import static org.apache.james.mailbox.cassandra.table.CassandraThreadTable.USERNAME;
+
+import org.apache.james.backends.cassandra.components.CassandraModule;
+
+public interface CassandraThreadModule {
+ CassandraModule MODULE = CassandraModule.builder()
+ .table(TABLE_NAME)
+ .comment("Related data needed for guessing threadId algorithm")
+ .statement(statement -> statement
+ .addPartitionKey(USERNAME, text())
+ .addPartitionKey(MIME_MESSAGE_ID, text())
+ .addClusteringColumn(MESSAGE_ID, timeuuid())
+ .addColumn(THREAD_ID, timeuuid())
+ .addColumn(BASE_SUBJECT, text()))
+ .build();
+
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraThreadTable.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraThreadTable.java
new file mode 100644
index 0000000..0db322a
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraThreadTable.java
@@ -0,0 +1,35 @@
+/******************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ******************************************************************/
+
+package org.apache.james.mailbox.cassandra.table;
+
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.THREAD_ID;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MESSAGE_ID;
+
+public interface CassandraThreadTable {
+ String TABLE_NAME = "threadTable";
+
+ String USERNAME = "username";
+
+ String MIME_MESSAGE_ID = "mimeMessageId";
+
+ String BASE_SUBJECT = "baseSubject";
+
+ String[] FIELDS = {MESSAGE_ID, THREAD_ID, USERNAME, MIME_MESSAGE_ID, BASE_SUBJECT};
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAOTest.java
new file mode 100644
index 0000000..1eee881
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAOTest.java
@@ -0,0 +1,190 @@
+/******************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ******************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import java.util.Optional;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.modules.CassandraThreadModule;
+import org.apache.james.mailbox.model.ThreadId;
+import org.apache.james.mailbox.store.mail.model.MimeMessageId;
+import org.apache.james.mailbox.store.mail.model.Subject;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class CassandraThreadDAOTest {
+ private static final Username ALICE = Username.of("alice");
+ private static final Username BOB = Username.of("bob");
+
+ @RegisterExtension
+ static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraThreadModule.MODULE);
+
+ private CassandraThreadDAO testee;
+ private CassandraMessageId messageId1;
+ private CassandraMessageId messageId2;
+ private CassandraMessageId messageId3;
+ private ThreadId threadId1;
+ private ThreadId threadId2;
+ private MimeMessageId mimeMessageId1;
+ private MimeMessageId mimeMessageId2;
+ private MimeMessageId mimeMessageId3;
+ private MimeMessageId mimeMessageId4;
+ private MimeMessageId mimeMessageId5;
+
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ testee = new CassandraThreadDAO(cassandra.getConf());
+
+ CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
+ messageId1 = messageIdFactory.generate();
+ messageId2 = messageIdFactory.generate();
+ messageId3 = messageIdFactory.generate();
+
+ threadId1 = ThreadId.fromBaseMessageId(messageId1);
+ threadId2 = ThreadId.fromBaseMessageId(messageId3);
+
+ mimeMessageId1 = new MimeMessageId("MimeMessageID1");
+ mimeMessageId2 = new MimeMessageId("MimeMessageID2");
+ mimeMessageId3 = new MimeMessageId("MimeMessageID3");
+ mimeMessageId4 = new MimeMessageId("MimeMessageID4");
+ mimeMessageId5 = new MimeMessageId("MimeMessageID5");
+ }
+
+ @Test
+ void insertShouldSuccess() {
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(message1BaseSubject, threadId1)));
+ }
+
+ @Test
+ void insertNullBaseSubjectShouldBeAllowed() {
+ Optional<Subject> message1BaseSubject = Optional.empty();
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(Optional.empty(), threadId1)));
+ }
+
+ @Test
+ void insertEmptyBaseSubjectShouldBeAllowed() {
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject(""));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(message1BaseSubject, threadId1)));
+ }
+
+ @Test
+ void selectShouldReturnEmptyByDefault() {
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1)).collectList().block()
+ .isEmpty());
+ }
+
+ @Test
+ void selectShouldReturnDistinctValues() {
+ Optional<Subject> messageBaseSubject = Optional.of(new Subject("subject"));
+
+ // given message1 and message2 belongs to same thread, related to each other by mimeMessageId2, mimeMessageId3
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2, mimeMessageId3), messageId1, threadId1, messageBaseSubject).collectList().block();
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId2, mimeMessageId3, mimeMessageId4), messageId2, threadId1, messageBaseSubject).collectList().block();
+
+ // select with new message having mimeMessageId2 and mimeMessageId3
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId2, mimeMessageId3)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(messageBaseSubject, threadId1)));
+ }
+
+ @Test
+ void selectShouldReturnOnlyRelatedMessageDataOfAUser() {
+ // insert message1 data of ALICE
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ // insert message2 data of BOB
+ Optional<Subject> message2BaseSubject = Optional.of(new Subject("subject2"));
+ testee.insertSome(BOB, ImmutableSet.of(mimeMessageId2), messageId2, threadId2, message2BaseSubject).collectList().block();
+
+ // select some data of BOB
+ assertThat(testee.selectSome(BOB, ImmutableSet.of(mimeMessageId2)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(message2BaseSubject, threadId2)));
+ }
+
+ @Test
+ void selectShouldReturnOnlyRelatedMessageDataOfAThread() {
+ // insert message1 data of ALICE which in thread1
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ // insert message2 data of ALICE which in thread2
+ Optional<Subject> message2BaseSubject = Optional.of(new Subject("subject2"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId2), messageId2, threadId2, message2BaseSubject).collectList().block();
+
+ // select some data related to thread2
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId2)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(message2BaseSubject, threadId2)));
+ }
+
+ @Test
+ void selectWithUnrelatedMimeMessageIDsShouldReturnEmpty() {
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId3, mimeMessageId4, mimeMessageId5)).collectList().block())
+ .isEqualTo(ImmutableList.of());
+ }
+
+ @Test
+ void deletedEntriesShouldNotBeReturned() {
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ testee.deleteSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2));
+
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2)).collectList().block()
+ .isEmpty());
+ }
+
+ @Test
+ void deleteWithUnrelatedMimeMessageIDsShouldDeleteNothing() {
+ // insert message1 data
+ Optional<Subject> message1BaseSubject = Optional.of(new Subject("subject"));
+ testee.insertSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2), messageId1, threadId1, message1BaseSubject).collectList().block();
+
+ // delete with unrelated mimemessageIds
+ testee.deleteSome(ALICE, ImmutableSet.of(mimeMessageId3, mimeMessageId4, mimeMessageId5));
+
+ // alice's data should remain
+ assertThat(testee.selectSome(ALICE, ImmutableSet.of(mimeMessageId1, mimeMessageId2)).collectList().block())
+ .isEqualTo(ImmutableList.of(Pair.of(message1BaseSubject, threadId1)));
+ }
+
+}
diff --git a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 0c94c90..e1140b1 100644
--- a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -129,6 +129,7 @@ public class CassandraMailboxModule extends AbstractModule {
install(new DefaultEventModule());
install(new CassandraQuotaModule());
install(new CassandraDeadLetterModule());
+ install(new CassandraThreadIdGuessingModule());
bind(CassandraApplicableFlagDAO.class).in(Scopes.SINGLETON);
bind(CassandraAttachmentDAOV2.class).in(Scopes.SINGLETON);
diff --git a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraThreadIdGuessingModule.java b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraThreadIdGuessingModule.java
new file mode 100644
index 0000000..6461f06
--- /dev/null
+++ b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraThreadIdGuessingModule.java
@@ -0,0 +1,39 @@
+/******************************************************************
+ * 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.modules.mailbox;
+
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.mailbox.cassandra.mail.CassandraThreadDAO;
+import org.apache.james.mailbox.cassandra.modules.CassandraThreadModule;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+import com.google.inject.multibindings.Multibinder;
+
+public class CassandraThreadIdGuessingModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(CassandraThreadDAO.class).in(Scopes.SINGLETON);
+
+ Multibinder.newSetBinder(binder(), CassandraModule.class)
+ .addBinding()
+ .toInstance(CassandraThreadModule.MODULE);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org