IMAP-370 Cassandra should implement move command
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/ea9d77de Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/ea9d77de Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/ea9d77de Branch: refs/heads/master Commit: ea9d77dee363f4b197ff42eece6a731f64d63b17 Parents: 8a29217 Author: Benoit Tellier <btell...@linagora.com> Authored: Tue Feb 23 16:11:15 2016 +0700 Committer: Benoit Tellier <btell...@linagora.com> Committed: Fri Mar 4 19:32:49 2016 +0700 ---------------------------------------------------------------------- .../cassandra/mail/CassandraMessageMapper.java | 48 +++--- .../mail/CassandraMessageMoveTest.java | 30 ++++ .../mail/model/AbstractMessageMoveTest.java | 145 +++++++++++++++++++ 3 files changed, 202 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/ea9d77de/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java index 1ec2348..c46447d 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java @@ -151,14 +151,18 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { @Override public void delete(Mailbox<CassandraId> mailbox, MailboxMessage<CassandraId> message) { + deleteUsingMailboxId(mailbox.getMailboxId(), message); + } + + private void deleteUsingMailboxId(CassandraId mailboxId, MailboxMessage<CassandraId> message) { session.execute( QueryBuilder.delete() .from(TABLE_NAME) - .where(eq(MAILBOX_ID, mailbox.getMailboxId().asUuid())) + .where(eq(MAILBOX_ID, mailboxId.asUuid())) .and(eq(IMAP_UID, message.getUid()))); - decrementCount(mailbox); + decrementCount(mailboxId); if (!message.isSeen()) { - decrementUnseen(mailbox); + decrementUnseen(mailboxId); } } @@ -196,8 +200,10 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { } @Override - public MessageMetaData move(Mailbox<CassandraId> mailbox, MailboxMessage<CassandraId> original) throws MailboxException { - throw new UnsupportedOperationException("Not implemented - see https://issues.apache.org/jira/browse/IMAP-370"); + public MessageMetaData move(Mailbox<CassandraId> destinationMailbox, MailboxMessage<CassandraId> original) throws MailboxException { + MessageMetaData messageMetaData = copy(destinationMailbox, original); + deleteUsingMailboxId(original.getMailboxId(), original); + return messageMetaData; } @Override @@ -216,9 +222,9 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { message.setModSeq(modSeqProvider.nextModSeq(mailboxSession, mailbox)); MessageMetaData messageMetaData = save(mailbox, message); if (!message.isSeen()) { - incrementUnseen(mailbox); + incrementUnseen(mailbox.getMailboxId()); } - incrementCount(mailbox); + incrementCount(mailbox.getMailboxId()); return messageMetaData; } @@ -243,9 +249,9 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { original.setUid(uidProvider.nextUid(mailboxSession, mailbox)); original.setModSeq(modSeqProvider.nextModSeq(mailboxSession, mailbox)); - incrementCount(mailbox); + incrementCount(mailbox.getMailboxId()); if(!original.isSeen()) { - incrementUnseen(mailbox); + incrementUnseen(mailbox.getMailboxId()); } original.setFlags(new FlagsBuilder().add(original.createFlags()).add(Flag.RECENT).build()); return save(mailbox, original); @@ -256,24 +262,24 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { return uidProvider.lastUid(mailboxSession, mailbox); } - private void decrementCount(Mailbox<CassandraId> mailbox) { - updateMailbox(mailbox, decr(CassandraMailboxCountersTable.COUNT)); + private void decrementCount(CassandraId mailboxId) { + updateMailbox(mailboxId, decr(CassandraMailboxCountersTable.COUNT)); } - private void incrementCount(Mailbox<CassandraId> mailbox) { - updateMailbox(mailbox, incr(CassandraMailboxCountersTable.COUNT)); + private void incrementCount(CassandraId mailboxId) { + updateMailbox(mailboxId, incr(CassandraMailboxCountersTable.COUNT)); } - private void decrementUnseen(Mailbox<CassandraId> mailbox) { - updateMailbox(mailbox, decr(CassandraMailboxCountersTable.UNSEEN)); + private void decrementUnseen(CassandraId mailboxId) { + updateMailbox(mailboxId, decr(CassandraMailboxCountersTable.UNSEEN)); } - private void incrementUnseen(Mailbox<CassandraId> mailbox) { - updateMailbox(mailbox, incr(CassandraMailboxCountersTable.UNSEEN)); + private void incrementUnseen(CassandraId mailboxId) { + updateMailbox(mailboxId, incr(CassandraMailboxCountersTable.UNSEEN)); } - private void updateMailbox(Mailbox<CassandraId> mailbox, Assignment operation) { - session.execute(update(CassandraMailboxCountersTable.TABLE_NAME).with(operation).where(eq(CassandraMailboxCountersTable.MAILBOX_ID, mailbox.getMailboxId().asUuid()))); + private void updateMailbox(CassandraId mailboxId, Assignment operation) { + session.execute(update(CassandraMailboxCountersTable.TABLE_NAME).with(operation).where(eq(CassandraMailboxCountersTable.MAILBOX_ID, mailboxId.asUuid()))); } private MailboxMessage<CassandraId> message(Row row) { @@ -366,10 +372,10 @@ public class CassandraMessageMapper implements MessageMapper<CassandraId> { private void manageUnseenMessageCounts(Mailbox<CassandraId> mailbox, Flags oldFlags, Flags newFlags) { if (oldFlags.contains(Flag.SEEN) && !newFlags.contains(Flag.SEEN)) { - incrementUnseen(mailbox); + incrementUnseen(mailbox.getMailboxId()); } if (!oldFlags.contains(Flag.SEEN) && newFlags.contains(Flag.SEEN)) { - decrementUnseen(mailbox); + decrementUnseen(mailbox.getMailboxId()); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/ea9d77de/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMoveTest.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMoveTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMoveTest.java new file mode 100644 index 0000000..51bc8c3 --- /dev/null +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMoveTest.java @@ -0,0 +1,30 @@ +/**************************************************************** + * 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 org.apache.james.mailbox.cassandra.CassandraId; +import org.apache.james.mailbox.store.mail.model.AbstractMessageMoveTest; + +public class CassandraMessageMoveTest extends AbstractMessageMoveTest<CassandraId> { + + public CassandraMessageMoveTest() { + super(new CassandraMapperProvider()); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/ea9d77de/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AbstractMessageMoveTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AbstractMessageMoveTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AbstractMessageMoveTest.java new file mode 100644 index 0000000..ed38feb --- /dev/null +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AbstractMessageMoveTest.java @@ -0,0 +1,145 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.mailbox.store.mail.model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Date; + +import javax.mail.Flags; +import javax.mail.util.SharedByteArrayInputStream; + +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageMetaData; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.store.mail.MessageMapper; +import org.apache.james.mailbox.store.mail.MessageMapper.FetchType; +import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; +import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox; +import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public abstract class AbstractMessageMoveTest<Id extends MailboxId> { + + private final static char DELIMITER = ':'; + private static final int LIMIT = 10; + private static final int BODY_START = 16; + public static final int UID_VALIDITY = 42; + + private MapperProvider<Id> mapperProvider; + private MessageMapper<Id> messageMapper; + + private SimpleMailbox<Id> benwaInboxMailbox; + private SimpleMailbox<Id> benwaWorkMailbox; + + private SimpleMailboxMessage<Id> message1; + + public AbstractMessageMoveTest(MapperProvider<Id> mapperProvider) { + this.mapperProvider = mapperProvider; + } + + @Before + public void setUp() throws MailboxException { + mapperProvider.ensureMapperPrepared(); + messageMapper = mapperProvider.createMessageMapper(); + benwaInboxMailbox = createMailbox(new MailboxPath("#private", "benwa", "INBOX")); + benwaWorkMailbox = createMailbox( new MailboxPath("#private", "benwa", "INBOX"+DELIMITER+"work")); + message1 = createMessage(benwaInboxMailbox, "Subject: Test1 \n\nBody1\n.\n", BODY_START, new PropertyBuilder()); + } + + @After + public void tearDown() throws MailboxException { + mapperProvider.clearMapper(); + } + + @Test + public void movingAMessageShouldWork() throws Exception { + messageMapper.add(benwaInboxMailbox, message1); + message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox)); + + messageMapper.move(benwaWorkMailbox, message1); + + assertThat(retrieveMessageFromStorage(benwaWorkMailbox, message1)).isEqualTo(message1); + } + + @Test + public void movingAMessageShouldReturnCorrectMetadata() throws Exception { + messageMapper.add(benwaInboxMailbox, message1); + message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox)); + + MessageMetaData messageMetaData = messageMapper.move(benwaWorkMailbox, message1); + + assertThat(messageMetaData.getFlags()).isEqualTo(message1.createFlags()); + assertThat(messageMetaData.getUid()).isEqualTo(messageMapper.getLastUid(benwaWorkMailbox)); + assertThat(messageMetaData.getModSeq()).isEqualTo(messageMapper.getHighestModSeq(benwaWorkMailbox)); + } + + @Test + public void movingAMessageShouldNotViolateMessageCount() throws Exception { + messageMapper.add(benwaInboxMailbox, message1); + message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox)); + + messageMapper.move(benwaWorkMailbox, message1); + + assertThat(messageMapper.countMessagesInMailbox(benwaInboxMailbox)).isEqualTo(0); + assertThat(messageMapper.countMessagesInMailbox(benwaWorkMailbox)).isEqualTo(1); + } + + @Test + public void movingAMessageShouldNotViolateUnseenMessageCount() throws Exception { + messageMapper.add(benwaInboxMailbox, message1); + message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox)); + + messageMapper.move(benwaWorkMailbox, message1); + + assertThat(messageMapper.countUnseenMessagesInMailbox(benwaInboxMailbox)).isEqualTo(0); + assertThat(messageMapper.countUnseenMessagesInMailbox(benwaWorkMailbox)).isEqualTo(1); + } + + @Test + public void movingASeenMessageShouldNotIncrementUnseenMessageCount() throws Exception { + message1.setFlags(new Flags(Flags.Flag.SEEN)); + messageMapper.add(benwaInboxMailbox, message1); + message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox)); + + messageMapper.move(benwaWorkMailbox, message1); + + assertThat(messageMapper.countUnseenMessagesInMailbox(benwaInboxMailbox)).isEqualTo(0); + assertThat(messageMapper.countUnseenMessagesInMailbox(benwaWorkMailbox)).isEqualTo(0); + } + + private SimpleMailbox<Id> createMailbox(MailboxPath mailboxPath) { + SimpleMailbox<Id> mailbox = new SimpleMailbox<Id>(mailboxPath, UID_VALIDITY); + Id id = mapperProvider.generateId(); + mailbox.setMailboxId(id); + return mailbox; + } + + private MailboxMessage<Id> retrieveMessageFromStorage(Mailbox<Id> mailbox, MailboxMessage<Id> message) throws MailboxException { + return messageMapper.findInMailbox(mailbox, MessageRange.one(message.getUid()), FetchType.Metadata, LIMIT).next(); + } + + private SimpleMailboxMessage<Id> createMessage(Mailbox<Id> mailbox, String content, int bodyStart, PropertyBuilder propertyBuilder) { + return new SimpleMailboxMessage<Id>(new Date(), content.length(), bodyStart, new SharedByteArrayInputStream(content.getBytes()), new Flags(), propertyBuilder, mailbox.getMailboxId()); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org