Skip to content

Commit

Permalink
JAMES-1644 (feature disabled) retrieve Message properties in GetMessa…
Browse files Browse the repository at this point in the history
…gesMethod

git-svn-id: https://svn.apache.org/repos/asf/james/project/trunk@1719394 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
mbaechler committed Dec 11, 2015
1 parent 8af7a90 commit 8099666
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 13 deletions.
Expand Up @@ -37,7 +37,7 @@ public class InMemoryMailboxMapper implements MailboxMapper<InMemoryId> {


private static final int INITIAL_SIZE = 128; private static final int INITIAL_SIZE = 128;
private final Map<InMemoryId, Mailbox<InMemoryId>> mailboxesById; private final Map<InMemoryId, Mailbox<InMemoryId>> mailboxesById;
private final static AtomicLong IDS = new AtomicLong(); private final AtomicLong mailboxIdGenerator = new AtomicLong();


public InMemoryMailboxMapper() { public InMemoryMailboxMapper() {
mailboxesById = new ConcurrentHashMap<InMemoryId, Mailbox<InMemoryId>>(INITIAL_SIZE); mailboxesById = new ConcurrentHashMap<InMemoryId, Mailbox<InMemoryId>>(INITIAL_SIZE);
Expand Down Expand Up @@ -99,7 +99,7 @@ private boolean mailboxMatchesRegex(Mailbox<InMemoryId> mailbox, MailboxPath pat
public void save(Mailbox<InMemoryId> mailbox) throws MailboxException { public void save(Mailbox<InMemoryId> mailbox) throws MailboxException {
InMemoryId id = mailbox.getMailboxId(); InMemoryId id = mailbox.getMailboxId();
if (id == null) { if (id == null) {
id = InMemoryId.of(IDS.incrementAndGet()); id = InMemoryId.of(mailboxIdGenerator.incrementAndGet());
((SimpleMailbox<InMemoryId>) mailbox).setMailboxId(id); ((SimpleMailbox<InMemoryId>) mailbox).setMailboxId(id);
} }
mailboxesById.put(id, mailbox); mailboxesById.put(id, mailbox);
Expand Down
Expand Up @@ -31,7 +31,9 @@
import org.apache.james.jmap.model.GetMessagesRequest; import org.apache.james.jmap.model.GetMessagesRequest;
import org.apache.james.jmap.model.GetMessagesResponse; import org.apache.james.jmap.model.GetMessagesResponse;
import org.apache.james.jmap.model.Message; import org.apache.james.jmap.model.Message;
import org.apache.james.jmap.model.Message.Builder;
import org.apache.james.jmap.model.MessageId; import org.apache.james.jmap.model.MessageId;
import org.apache.james.jmap.model.Property;
import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MessageRange;
Expand All @@ -43,8 +45,11 @@
import org.javatuples.Pair; import org.javatuples.Pair;


import com.github.fge.lambdas.Throwing; import com.github.fge.lambdas.Throwing;
import com.github.fge.lambdas.functions.ThrowingBiFunction;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;


public class GetMessagesMethod<Id extends MailboxId> implements Method { public class GetMessagesMethod<Id extends MailboxId> implements Method {


Expand Down Expand Up @@ -79,11 +84,13 @@ public GetMessagesResponse process(JmapRequest request, MailboxSession mailboxSe
GetMessagesRequest getMessagesRequest = (GetMessagesRequest) request; GetMessagesRequest getMessagesRequest = (GetMessagesRequest) request;


Function<MessageId, Stream<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, MailboxPath>>> loadMessages = loadMessage(mailboxSession); Function<MessageId, Stream<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, MailboxPath>>> loadMessages = loadMessage(mailboxSession);
Function<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, MailboxPath>, Message> toJmapMessage = toJmapMessage(mailboxSession); Function<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, MailboxPath>, Message> convertToJmapMessage = toJmapMessage(mailboxSession);
Function<Message, Message> filterFields = new JmapMessageFactory(getMessagesRequest);


List<Message> result = getMessagesRequest.getIds().stream() List<Message> result = getMessagesRequest.getIds().stream()
.flatMap(loadMessages) .flatMap(loadMessages)
.map(toJmapMessage) .map(convertToJmapMessage)
// .map(filterFields)
.collect(Collectors.toList()); .collect(Collectors.toList());


return new GetMessagesResponse(result); return new GetMessagesResponse(result);
Expand All @@ -101,7 +108,6 @@ private Function<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, Mai
Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, Pair<org.apache.james.mailbox.store.mail.model.Message<Id>,
MailboxPath>>> MailboxPath>>>
loadMessage(MailboxSession mailboxSession) { loadMessage(MailboxSession mailboxSession) {

return Throwing return Throwing
.function((MessageId messageId) -> { .function((MessageId messageId) -> {
MailboxPath mailboxPath = messageId.getMailboxPath(mailboxSession); MailboxPath mailboxPath = messageId.getMailboxPath(mailboxSession);
Expand All @@ -123,4 +129,33 @@ private Stream<Pair<org.apache.james.mailbox.store.mail.model.Message<Id>, Mailb
return targetStream.map(x -> Pair.with(x, mailboxPath)); return targetStream.map(x -> Pair.with(x, mailboxPath));
} }


private static class JmapMessageFactory implements Function<Message, Message> {

public ImmutableMap<Property, ThrowingBiFunction<Message, Message.Builder, Message.Builder>> fieldCopiers =
ImmutableMap.of(
Property.id, (message, builder) -> builder.id(message.getId()),
Property.subject, (message, builder) -> builder.subject(message.getSubject())
);

private final ImmutableList<Property> selectedProperties;

public JmapMessageFactory(GetMessagesRequest messagesRequest) {
this.selectedProperties = messagesRequest.getProperties().orElse(Property.all());
}

@Override
public Message apply(Message input) {
Message.Builder builder = Message.builder();

selectCopiers().forEach(f -> f.apply(input, builder));

return builder.build();
}

private Stream<ThrowingBiFunction<Message, Builder, Builder>> selectCopiers() {
return Stream.concat(selectedProperties.stream(), Stream.of(Property.id))
.filter(fieldCopiers::containsKey)
.map(fieldCopiers::get);
}
}
} }
Expand Up @@ -285,4 +285,5 @@ public final int hashCode() {
return Objects.hash(id, name, parentId, role, sortOrder, mustBeOnlyMailbox, mayReadItems, mayAddItems, return Objects.hash(id, name, parentId, role, sortOrder, mustBeOnlyMailbox, mayReadItems, mayAddItems,
mayRemoveItems, mayCreateChild, mayRename, mayDelete, totalMessages, unreadMessages, totalThreads, unreadThreads); mayRemoveItems, mayCreateChild, mayRename, mayDelete, totalMessages, unreadMessages, totalThreads, unreadThreads);
} }

} }
Expand Up @@ -18,6 +18,47 @@
****************************************************************/ ****************************************************************/
package org.apache.james.jmap.model; package org.apache.james.jmap.model;


public class Property { import com.google.common.collect.ImmutableList;


public enum Property {
id("id"),
blobId("blobId"),
threadId("threadId"),
mailboxIds("mailboxIds"),
inReplyToMessageId("inReplyToMessageId"),
isUnread("isUnread"),
isFlagged("isFlagged"),
isAnswered("isAnswered"),
isDraft("isDraft"),
hasAttachment("hasAttachment"),
headers("headers"),
from("from"),
to("to"),
cc("cc"),
bcc("bcc"),
replyTo("replyTo"),
subject("subject"),
date("date"),
size("size"),
preview("preview"),
textBody("textBody"),
htmlBody("htmlBody"),
attachments("attachments"),
attachedMessages("attachedMessages"),
body("body"),
headers_property("headers.property");

private String property;

private Property(String property) {
this.property = property;
}

public String getProperty() {
return property;
}

public static ImmutableList<Property> all() {
return ImmutableList.copyOf(values());
}
} }
Expand Up @@ -29,7 +29,9 @@


import org.apache.james.jmap.model.GetMessagesRequest; import org.apache.james.jmap.model.GetMessagesRequest;
import org.apache.james.jmap.model.GetMessagesResponse; import org.apache.james.jmap.model.GetMessagesResponse;
import org.apache.james.jmap.model.Message;
import org.apache.james.jmap.model.MessageId; import org.apache.james.jmap.model.MessageId;
import org.apache.james.jmap.model.Property;
import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver; import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
Expand All @@ -40,6 +42,7 @@
import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.MockAuthenticator; import org.apache.james.mailbox.store.MockAuthenticator;
import org.apache.james.mailbox.store.StoreMailboxManager; import org.apache.james.mailbox.store.StoreMailboxManager;
import org.assertj.core.groups.Tuple;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
Expand Down Expand Up @@ -120,11 +123,13 @@ public void processShouldThrowWhenNullSession() {
@Test @Test
public void processShouldFetchMessages() throws MailboxException { public void processShouldFetchMessages() throws MailboxException {
MessageManager inbox = mailboxManager.getMailbox(inboxPath, session); MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
ByteArrayInputStream messageContent = new ByteArrayInputStream("my message".getBytes(Charsets.UTF_8));
Date now = new Date(); Date now = new Date();
long message1Uid = inbox.appendMessage(messageContent, now, session, false, null); ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message2Uid = inbox.appendMessage(messageContent, now, session, false, null); long message1Uid = inbox.appendMessage(message1Content, now, session, false, null);
long message3Uid = inbox.appendMessage(messageContent, now, session, false, null); ByteArrayInputStream message2Content = new ByteArrayInputStream("Subject: message 2 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message2Uid = inbox.appendMessage(message2Content, now, session, false, null);
ByteArrayInputStream message3Content = new ByteArrayInputStream("Great-Header: message 3 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message3Uid = inbox.appendMessage(message3Content, now, session, false, null);


GetMessagesRequest request = GetMessagesRequest.builder() GetMessagesRequest request = GetMessagesRequest.builder()
.ids(new MessageId(ROBERT, inboxPath, message1Uid), .ids(new MessageId(ROBERT, inboxPath, message1Uid),
Expand All @@ -135,7 +140,71 @@ public void processShouldFetchMessages() throws MailboxException {
GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory);
GetMessagesResponse result = testee.process(request, session); GetMessagesResponse result = testee.process(request, session);


assertThat(result.list()).extracting(message -> message.getId().getUid()).containsOnly(message1Uid, message2Uid, message3Uid); assertThat(result.list())
.extracting(message -> message.getId().getUid(), Message::getSubject)
.containsOnly(
Tuple.tuple(message1Uid, "message 1 subject"),
Tuple.tuple(message2Uid, "message 2 subject"),
Tuple.tuple(message3Uid, "(No subject)"));
}

@Test
public void processShouldReturnOnlyMessageIdsOnEmptyPropertyList() throws MailboxException {
MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
Date now = new Date();
ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message1Uid = inbox.appendMessage(message1Content, now, session, false, null);

GetMessagesRequest request = GetMessagesRequest.builder()
.ids(new MessageId(ROBERT, inboxPath, message1Uid))
.properties(new Property[0])
.build();

GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory);
GetMessagesResponse result = testee.process(request, session);

assertThat(result.list())
.extracting(message -> message.getId().getUid(), Message::getSubject)
.containsOnly(Tuple.tuple(message1Uid, "message 1 subject"));
}

@Test
public void processShouldReturnIdWhenNotInPropertyList() throws MailboxException {
MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
Date now = new Date();
ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message1Uid = inbox.appendMessage(message1Content, now, session, false, null);

GetMessagesRequest request = GetMessagesRequest.builder()
.ids(new MessageId(ROBERT, inboxPath, message1Uid))
.properties(Property.subject)
.build();

GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory);
GetMessagesResponse result = testee.process(request, session);

assertThat(result.list())
.extracting(message -> message.getId().getUid(), Message::getSubject)
.containsOnly(Tuple.tuple(message1Uid, "message 1 subject"));
} }


@Test
public void processShouldReturnAllFieldsWhenUndefinedPropertyList() throws MailboxException {
MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
Date now = new Date();
ByteArrayInputStream message1Content = new ByteArrayInputStream("Subject: message 1 subject\r\n\r\nmy message".getBytes(Charsets.UTF_8));
long message1Uid = inbox.appendMessage(message1Content, now, session, false, null);

GetMessagesRequest request = GetMessagesRequest.builder()
.ids(new MessageId(ROBERT, inboxPath, message1Uid))
.build();

GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory);
GetMessagesResponse result = testee.process(request, session);

assertThat(result.list())
.extracting(message -> message.getId().getUid(), Message::getSubject)
.containsOnly(Tuple.tuple(message1Uid, "message 1 subject"));
}

} }
Expand Up @@ -29,7 +29,7 @@ public class GetMessagesRequestTest {


@Test @Test
public void shouldAllowOptionalAccountId() { public void shouldAllowOptionalAccountId() {
GetMessagesRequest result = GetMessagesRequest.builder().ids(MessageId.of("user-inbox-1")).properties(new Property()).build(); GetMessagesRequest result = GetMessagesRequest.builder().ids(MessageId.of("user-inbox-1")).properties(Property.id).build();
assertThat(result).isNotNull(); assertThat(result).isNotNull();
assertThat(result.getAccountId()).isEmpty(); assertThat(result.getAccountId()).isEmpty();
} }
Expand All @@ -41,7 +41,7 @@ public void shouldThrowWhenAccountIdIsNull() {


@Test @Test
public void shouldAllowEmptyMessagesList() { public void shouldAllowEmptyMessagesList() {
GetMessagesRequest result = GetMessagesRequest.builder().accountId("accountId").ids().properties(new Property()).build(); GetMessagesRequest result = GetMessagesRequest.builder().accountId("accountId").ids().properties(Property.id).build();
assertThat(result).isNotNull(); assertThat(result).isNotNull();
assertThat(result.getIds()).isEmpty(); assertThat(result.getIds()).isEmpty();
} }
Expand Down

0 comments on commit 8099666

Please sign in to comment.