JAMES-1691 After sending a mail, move it from OUTBOX to SENT
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/a7d66019 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/a7d66019 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/a7d66019 Branch: refs/heads/master Commit: a7d660195fc4bb3ac47337bf6c2cde65deafc284 Parents: 6d7e683 Author: Raphael Ouazana <[email protected]> Authored: Mon Feb 22 17:08:55 2016 +0100 Committer: Raphael Ouazana <[email protected]> Committed: Tue Mar 1 14:44:59 2016 +0100 ---------------------------------------------------------------------- .../modules/server/ActiveMQQueueModule.java | 23 +- .../apache/james/jmap/send/MailMetadata.java | 64 +++++ .../org/apache/james/jmap/send/MailSpool.java | 4 +- .../james/jmap/send/PostDequeueDecorator.java | 159 ++++++++++++ .../jmap/send/PostDequeueDecoratorFactory.java | 51 ++++ .../MailShouldBeInOutboxException.java | 30 +++ .../exception/MailboxRoleNotFoundException.java | 30 +++ .../exception/MessageIdNotFoundException.java | 30 +++ .../james/jmap/send/MailMetadataTest.java | 38 +++ .../apache/james/jmap/send/MailSpoolTest.java | 3 +- .../jmap/send/PostDequeueDecoratorTest.java | 257 +++++++++++++++++++ 11 files changed, 674 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/container/cassandra-guice/src/main/java/org/apache/james/modules/server/ActiveMQQueueModule.java ---------------------------------------------------------------------- diff --git a/server/container/cassandra-guice/src/main/java/org/apache/james/modules/server/ActiveMQQueueModule.java b/server/container/cassandra-guice/src/main/java/org/apache/james/modules/server/ActiveMQQueueModule.java index 92d972c..e7602bb 100644 --- a/server/container/cassandra-guice/src/main/java/org/apache/james/modules/server/ActiveMQQueueModule.java +++ b/server/container/cassandra-guice/src/main/java/org/apache/james/modules/server/ActiveMQQueueModule.java @@ -19,16 +19,20 @@ package org.apache.james.modules.server; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; +import javax.jms.ConnectionFactory; + +import org.apache.james.jmap.send.PostDequeueDecoratorFactory; +import org.apache.james.mailbox.cassandra.CassandraId; import org.apache.james.queue.activemq.ActiveMQMailQueueFactory; -import org.apache.james.queue.api.MailQueueItemDecoratorFactory; import org.apache.james.queue.api.MailQueueFactory; +import org.apache.james.queue.api.MailQueueItemDecoratorFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.jms.ConnectionFactory; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.TypeLiteral; public class ActiveMQQueueModule extends AbstractModule { @@ -36,7 +40,7 @@ public class ActiveMQQueueModule extends AbstractModule { @Override protected void configure() { - + bind(MailQueueItemDecoratorFactory.class).to(new TypeLiteral<PostDequeueDecoratorFactory<CassandraId>>(){}).in(Singleton.class); } @Provides @@ -53,11 +57,4 @@ public class ActiveMQQueueModule extends AbstractModule { activeMQMailQueueFactory.init(); return activeMQMailQueueFactory; } - - @Provides - @Singleton - public MailQueueItemDecoratorFactory defaultMailQueueItemDecoratorFactory() { - return MailQueueItemDecoratorFactory.RAW_FACTORY; - } - } http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java new file mode 100644 index 0000000..319ba21 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.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.jmap.send; + +import java.util.Objects; + +import org.apache.james.jmap.model.MessageId; + +import com.google.common.base.Preconditions; + +public class MailMetadata { + public static final String MAIL_METADATA_MESSAGE_ID_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.messageId"; + public static final String MAIL_METADATA_USERNAME_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.username"; + + private final MessageId messageId; + private final String username; + + public MailMetadata(MessageId messageId, String username) { + Preconditions.checkNotNull(messageId); + Preconditions.checkNotNull(username); + this.messageId = messageId; + this.username = username; + } + + public MessageId getMessageId() { + return messageId; + } + + public String getUsername() { + return username; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MailMetadata) { + MailMetadata other = (MailMetadata) obj; + return Objects.equals(this.messageId, other.messageId) + && Objects.equals(this.username, other.username); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(messageId, username); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java index 6267890..a5b686d 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java @@ -37,7 +37,9 @@ public class MailSpool { queue = queueFactory.getQueue(MailQueueFactory.SPOOL); } - public void send(Mail mail) throws MailQueueException { + public void send(Mail mail, MailMetadata metadata) throws MailQueueException { + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, metadata.getMessageId().serialize()); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, metadata.getUsername()); queue.enQueue(mail); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java new file mode 100644 index 0000000..6722ef7 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java @@ -0,0 +1,159 @@ +/**************************************************************** + * 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.send; + +import java.io.Serializable; +import java.util.Iterator; + +import org.apache.james.jmap.model.MessageId; +import org.apache.james.jmap.model.mailbox.Role; +import org.apache.james.jmap.send.exception.MailShouldBeInOutboxException; +import org.apache.james.jmap.send.exception.MailboxRoleNotFoundException; +import org.apache.james.jmap.send.exception.MessageIdNotFoundException; +import org.apache.james.mailbox.MailboxManager; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxMetaData; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MailboxQuery; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.store.mail.MailboxMapperFactory; +import org.apache.james.mailbox.store.mail.MessageMapper; +import org.apache.james.mailbox.store.mail.MessageMapperFactory; +import org.apache.james.mailbox.store.mail.model.Mailbox; +import org.apache.james.mailbox.store.mail.model.MailboxId; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.queue.api.MailQueue.MailQueueException; +import org.apache.james.queue.api.MailQueue.MailQueueItem; +import org.apache.james.queue.api.MailQueueItemDecoratorFactory.MailQueueItemDecorator; +import org.apache.mailet.Mail; +import org.javatuples.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PostDequeueDecorator<Id extends MailboxId> extends MailQueueItemDecorator { + private static final Logger LOG = LoggerFactory.getLogger(PostDequeueDecorator.class); + + private final MailboxManager mailboxManager; + private final MessageMapperFactory<Id> messageMapperFactory; + private final MailboxMapperFactory<Id> mailboxMapperFactory; + + public PostDequeueDecorator(MailQueueItem mailQueueItem, + MailboxManager mailboxManager, + MessageMapperFactory<Id> messageMapperFactory, + MailboxMapperFactory<Id> mailboxMapperFactory) { + super(mailQueueItem); + this.mailboxManager = mailboxManager; + this.messageMapperFactory = messageMapperFactory; + this.mailboxMapperFactory = mailboxMapperFactory; + } + + @Override + public Mail getMail() { + return mailQueueItem.getMail(); + } + + @Override + public void done(boolean success) throws MailQueueException { + mailQueueItem.done(success); + if (success && mandatoryJmapMetaDataIsPresent()) { + MessageId messageId = MessageId.of((String) getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE)); + String username = (String) getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE); + try { + MailboxSession mailboxSession = mailboxManager.createSystemSession(username, LOG); + Pair<MailboxMessage<Id>, MailboxPath> mailboxMessageAndMailboxPath = getMailboxMessageAndMailboxPath(messageId, mailboxSession); + moveFromOutboxToSent(mailboxMessageAndMailboxPath, mailboxSession); + } catch (MailboxException e) { + throw new MailQueueException(e.getMessage(), e); + } + } + } + + private boolean mandatoryJmapMetaDataIsPresent() { + return checkMessageIdAttribute() + && checkUsernameAttribute(); + } + + private boolean checkMessageIdAttribute() { + Serializable messageId = getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE); + if (messageId == null || ! (messageId instanceof String)) { + return false; + } + try { + MessageId.of((String) messageId); + } catch (Exception e) { + LOG.error("Invalid messageId: " + (String) messageId); + return false; + } + return true; + } + + private boolean checkUsernameAttribute() { + Serializable username = getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE); + return (username != null && username instanceof String); + } + + public Pair<MailboxMessage<Id>, MailboxPath> getMailboxMessageAndMailboxPath(MessageId messageId, MailboxSession mailboxSession) throws MailQueueException, MailboxException { + MailboxPath mailboxPath = messageId.getMailboxPath(); + MessageMapper<Id> messageMapper = messageMapperFactory.getMessageMapper(mailboxSession); + Mailbox<Id> mailbox = mailboxMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(mailboxPath); + Iterator<MailboxMessage<Id>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(messageId.getUid()), MessageMapper.FetchType.Full, 1); + if (resultIterator.hasNext()) { + return Pair.with(resultIterator.next(), mailboxPath); + } else { + throw new MessageIdNotFoundException(messageId); + } + } + + private void moveFromOutboxToSent(Pair<MailboxMessage<Id>, MailboxPath> mailboxMessageAndMailboxPath, MailboxSession mailboxSession) throws MailQueueException, MailboxException { + MailboxMessage<Id> mailboxMessage = mailboxMessageAndMailboxPath.getValue0(); + MailboxPath outboxMailboxPath = mailboxMessageAndMailboxPath.getValue1(); + ensureMailboxPathIsOutbox(outboxMailboxPath); + MailboxPath sentMailboxPath = getSentMailboxPath(mailboxSession); + + // MOVE is not implemented, so COPY and DELETE + mailboxManager.copyMessages(MessageRange.one(mailboxMessage.getUid()), outboxMailboxPath, sentMailboxPath, mailboxSession); + Mailbox<Id> outboxMailbox = mailboxMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(outboxMailboxPath); + messageMapperFactory.getMessageMapper(mailboxSession).delete(outboxMailbox, mailboxMessage); + } + + private void ensureMailboxPathIsOutbox(MailboxPath outboxMailboxPath) throws MailShouldBeInOutboxException { + if (!hasRole(outboxMailboxPath, Role.OUTBOX)) { + throw new MailShouldBeInOutboxException(outboxMailboxPath); + } + } + + private MailboxPath getSentMailboxPath(MailboxSession session) throws MailboxRoleNotFoundException, MailboxException { + MailboxQuery allUserMailboxesQuery = MailboxQuery.builder(session) + .privateUserMailboxes() + .build(); + return mailboxManager.search(allUserMailboxesQuery, session) + .stream() + .map(MailboxMetaData::getPath) + .filter(path -> hasRole(path, Role.SENT)) + .findFirst() + .orElseThrow(() -> new MailboxRoleNotFoundException(Role.SENT)); + } + + private boolean hasRole(MailboxPath mailBoxPath, Role role) { + return Role.from(mailBoxPath.getName()) + .map(role::equals) + .orElse(false); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecoratorFactory.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecoratorFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecoratorFactory.java new file mode 100644 index 0000000..24797fc --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecoratorFactory.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.send; + +import org.apache.james.queue.api.MailQueue.MailQueueItem; + +import javax.inject.Inject; + +import org.apache.james.mailbox.MailboxManager; +import org.apache.james.mailbox.store.mail.MailboxMapperFactory; +import org.apache.james.mailbox.store.mail.MessageMapperFactory; +import org.apache.james.mailbox.store.mail.model.MailboxId; +import org.apache.james.queue.api.MailQueueItemDecoratorFactory; + +public class PostDequeueDecoratorFactory<Id extends MailboxId> implements MailQueueItemDecoratorFactory { + private final MailboxManager mailboxManager; + private final MessageMapperFactory<Id> messageMapperFactory; + private final MailboxMapperFactory<Id> mailboxMapperFactory; + + @Inject + public PostDequeueDecoratorFactory(MailboxManager mailboxManager, + MessageMapperFactory<Id> messageMapperFactory, + MailboxMapperFactory<Id> mailboxMapperFactory) { + this.mailboxManager = mailboxManager; + this.messageMapperFactory = messageMapperFactory; + this.mailboxMapperFactory = mailboxMapperFactory; + } + + @Override + public MailQueueItemDecorator decorate(MailQueueItem mailQueueItem) { + return new PostDequeueDecorator<Id>(mailQueueItem, mailboxManager, messageMapperFactory, mailboxMapperFactory); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailShouldBeInOutboxException.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailShouldBeInOutboxException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailShouldBeInOutboxException.java new file mode 100644 index 0000000..f0e781b --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailShouldBeInOutboxException.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.jmap.send.exception; + +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.queue.api.MailQueue.MailQueueException; + +public class MailShouldBeInOutboxException extends MailQueueException { + + public MailShouldBeInOutboxException(MailboxPath mailboxPath) { + super("Mail to be sent should be in OUTBOX but is in " + mailboxPath.getName()); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailboxRoleNotFoundException.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailboxRoleNotFoundException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailboxRoleNotFoundException.java new file mode 100644 index 0000000..39d73e1 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MailboxRoleNotFoundException.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.jmap.send.exception; + +import org.apache.james.jmap.model.mailbox.Role; +import org.apache.james.queue.api.MailQueue.MailQueueException; + +public class MailboxRoleNotFoundException extends MailQueueException { + + public MailboxRoleNotFoundException(Role role) { + super("Unable to find a mailbox with role " + role.name()); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MessageIdNotFoundException.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MessageIdNotFoundException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MessageIdNotFoundException.java new file mode 100644 index 0000000..0db7817 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/exception/MessageIdNotFoundException.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.jmap.send.exception; + +import org.apache.james.jmap.model.MessageId; +import org.apache.james.queue.api.MailQueue.MailQueueException; + +public class MessageIdNotFoundException extends MailQueueException { + + public MessageIdNotFoundException(MessageId messageId) { + super("Unable to find a Mailbox Message matching: " + messageId.serialize()); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailMetadataTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailMetadataTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailMetadataTest.java new file mode 100644 index 0000000..b080077 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailMetadataTest.java @@ -0,0 +1,38 @@ +/**************************************************************** + * 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.send; + +import org.apache.james.jmap.model.MessageId; +import org.junit.Test; + +public class MailMetadataTest { + + private static final MessageId MESSAGE_ID = MessageId.of("username|path|0"); + private static final String USERNAME = "username"; + + @Test(expected=NullPointerException.class) + public void constructorShouldThrowWhenNullMessageId() { + new MailMetadata(null, USERNAME); + } + + @Test(expected=NullPointerException.class) + public void constructorShouldThrowWhenNullUsername() { + new MailMetadata(MESSAGE_ID, null); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java index 3687138..667e0ee 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java @@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; +import org.apache.james.jmap.model.MessageId; import org.apache.james.queue.api.MailQueue; import org.apache.james.queue.api.MailQueue.MailQueueException; import org.apache.james.queue.api.MailQueue.MailQueueItem; @@ -55,7 +56,7 @@ public class MailSpoolTest { public void sendShouldEnQueueTheMail() throws Exception { FakeMail mail = new FakeMail(); - mailSpool.send(mail); + mailSpool.send(mail, new MailMetadata(MessageId.of("a|b|1"), "user")); assertThat(myQueue.deQueue()) .isNotNull() http://git-wip-us.apache.org/repos/asf/james-project/blob/a7d66019/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java new file mode 100644 index 0000000..fff82f1 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java @@ -0,0 +1,257 @@ +/**************************************************************** + * 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.send; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.util.Date; +import java.util.Iterator; + +import javax.mail.Flags; + +import org.apache.james.jmap.model.MessageId; +import org.apache.james.jmap.send.exception.MailShouldBeInOutboxException; +import org.apache.james.jmap.send.exception.MailboxRoleNotFoundException; +import org.apache.james.jmap.send.exception.MessageIdNotFoundException; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.acl.GroupMembershipResolver; +import org.apache.james.mailbox.acl.MailboxACLResolver; +import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver; +import org.apache.james.mailbox.acl.UnionMailboxACLResolver; +import org.apache.james.mailbox.inmemory.InMemoryId; +import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory; +import org.apache.james.mailbox.model.MailboxConstants; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.store.MockAuthenticator; +import org.apache.james.mailbox.store.StoreMailboxManager; +import org.apache.james.mailbox.store.mail.MessageMapper; +import org.apache.james.mailbox.store.mail.model.Mailbox; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.queue.api.MailQueue.MailQueueItem; +import org.apache.mailet.Mail; +import org.apache.mailet.base.test.FakeMail; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PostDequeueDecoratorTest { + private static final Logger LOGGER = LoggerFactory.getLogger(PostDequeueDecoratorTest.class); + private static final String OUTBOX = "OUTBOX"; + private static final String SENT = "SENT"; + private static final String USERNAME = "[email protected]"; + private static final long UID = 1; + private static final MailboxPath OUTBOX_MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, OUTBOX); + private static final MailboxPath SENT_MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, SENT); + private static final String MESSAGE_ID = USERNAME + "|" + OUTBOX_MAILBOX_PATH.getName() + "|" + UID; + + private InMemoryMailboxSessionMapperFactory mailboxSessionMapperFactory; + private StoreMailboxManager<InMemoryId> mailboxManager; + private MailQueueItem mockedMailQueueItem; + private Mail mail; + private PostDequeueDecorator<InMemoryId> testee; + + @Before + public void init() throws Exception { + mailboxSessionMapperFactory = new InMemoryMailboxSessionMapperFactory(); + MailboxACLResolver aclResolver = new UnionMailboxACLResolver(); + GroupMembershipResolver groupMembershipResolver = new SimpleGroupMembershipResolver(); + mailboxManager = new StoreMailboxManager<>(mailboxSessionMapperFactory, new MockAuthenticator(), aclResolver, groupMembershipResolver); + mailboxManager.init(); + + mockedMailQueueItem = mock(MailQueueItem.class); + mail = new FakeMail(); + when(mockedMailQueueItem.getMail()).thenReturn(mail); + testee = new PostDequeueDecorator<InMemoryId>(mockedMailQueueItem, mailboxManager, mailboxSessionMapperFactory, mailboxSessionMapperFactory); + } + + @Test + public void doneShouldCallDecoratedDone() throws Exception { + try { + testee.done(true); + } catch (Exception e) { + //Ignore + } + + verify(mockedMailQueueItem).done(true); + } + + @Test(expected=MessageIdNotFoundException.class) + public void doneShouldThrowWhenMetadataHasNotAnExistingMessageId() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + } + + @Test(expected=MailShouldBeInOutboxException.class) + public void doneShouldThrowWhenMessageIsNotInOutbox() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(SENT_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + MessageId inSentMessageId = MessageId.of(USERNAME + "|" + SENT_MAILBOX_PATH.getName() + "|" + UID); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, inSentMessageId.serialize()); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + } + + @Test(expected=MailboxRoleNotFoundException.class) + public void doneShouldThrowWhenSentDoesNotExist() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + } + + @Test + public void doneShouldCopyMailFromOutboxToSentWhenSuccess() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + + Mailbox<InMemoryId> sentMailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(SENT_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(sentMailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } + + @Test + public void doneShouldDeleteMailFromOutboxWhenSuccess() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(0); + } + + @Test + public void doneShouldNotMoveMailFromOutboxToSentWhenSuccessIsFalse() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(false); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } + + @Test + public void doneShouldNotMoveMailFromOutboxToSentWhenNoMetadataProvided() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + + testee.done(true); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } + + @Test + public void doneShouldNotMoveMailFromOutboxToSentWhenUsernameNotProvided() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, MESSAGE_ID); + + testee.done(true); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } + + @Test + public void doneShouldNotMoveMailFromOutboxToSentWhenMessageIdNotProvided() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + + testee.done(true); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } + + @Test + public void doneShouldNotMoveMailFromOutboxToSentWhenInvalidMessageIdProvided() throws Exception { + MailboxSession mailboxSession = mailboxManager.createSystemSession(USERNAME, LOGGER); + mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession); + MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession); + messageManager.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), mailboxSession, false, new Flags()); + mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME); + mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, "invalid"); + + testee.done(true); + + Mailbox<InMemoryId> mailbox = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).findMailboxByPath(OUTBOX_MAILBOX_PATH); + MessageMapper<InMemoryId> messageMapper = mailboxSessionMapperFactory.getMessageMapper(mailboxSession); + Iterator<MailboxMessage<InMemoryId>> resultIterator = messageMapper.findInMailbox(mailbox, MessageRange.one(UID), MessageMapper.FetchType.Full, 1); + assertThat(resultIterator).hasSize(1); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
