JAMES-1664 Add mandatory fields threadId & mailboxIds to GetMessages response
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7dfe3e55 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7dfe3e55 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7dfe3e55 Branch: refs/heads/master Commit: 7dfe3e5548bf56e863545a2fd81ea0a821b5375a Parents: a2a6825 Author: Antoine Duprat <antdup...@gmail.com> Authored: Fri Jan 22 12:06:04 2016 +0100 Committer: Antoine Duprat <antdup...@gmail.com> Committed: Mon Feb 1 13:21:05 2016 +0100 ---------------------------------------------------------------------- .../org/apache/james/jmap/MethodsModule.java | 4 +- .../jmap/methods/GetMessagesMethodTest.java | 35 +++++++- .../james/jmap/methods/GetMessagesMethod.java | 85 +++++++++++--------- .../james/jmap/model/GetMessagesRequest.java | 56 +++++++++++-- .../james/jmap/model/MessageHeaderProperty.java | 69 ++++++++++++++++ .../james/jmap/model/MessageProperty.java | 35 ++------ .../jmap/methods/GetMessagesMethodTest.java | 48 ++++++++--- .../jmap/model/GetMailboxesRequestTest.java | 27 +++++++ .../jmap/model/GetMessagesRequestTest.java | 40 +++++++-- .../jmap/model/MessageHeaderPropertyTest.java | 58 +++++++++++++ .../james/jmap/model/MessagePropertyTest.java | 52 +----------- 11 files changed, 372 insertions(+), 137 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java ---------------------------------------------------------------------- diff --git a/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java b/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java index 949a87d..4f1d64f 100644 --- a/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java +++ b/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java @@ -19,7 +19,6 @@ package org.apache.james.jmap; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.apache.james.jmap.methods.GetMailboxesMethod; import org.apache.james.jmap.methods.GetMessageListMethod; import org.apache.james.jmap.methods.GetMessagesMethod; @@ -31,7 +30,9 @@ import org.apache.james.jmap.methods.Method; import org.apache.james.mailbox.cassandra.CassandraId; import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.datatype.guava.GuavaModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.inject.AbstractModule; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; @@ -45,6 +46,7 @@ public class MethodsModule extends AbstractModule { Multibinder<Module> jacksonModules = Multibinder.newSetBinder(binder(), Module.class); jacksonModules.addBinding().to(Jdk8Module.class); jacksonModules.addBinding().to(JavaTimeModule.class); + jacksonModules.addBinding().to(GuavaModule.class); bind(JmapRequestParser.class).to(JmapRequestParserImpl.class).in(Singleton.class); bind(JmapResponseWriter.class).to(JmapResponseWriterImpl.class).in(Singleton.class); http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java index 8d217e2..50508ca 100644 --- a/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java +++ b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java @@ -174,7 +174,7 @@ public abstract class GetMessagesMethodTest { assertThat(JsonPath.parse(response).<Integer>read("$.length()")).isEqualTo(1); assertThat(JsonPath.parse(response).<List<String>>read("$.[0].[1].notFound")).containsExactly("username|inbox|12"); } - + @Test public void getMessagesShouldReturnMessagesWhenAvailable() throws Exception { jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "inbox"); @@ -320,4 +320,37 @@ public abstract class GetMessagesMethodTest { assertThat(jsonPath.parse(response).<Integer>read(firstResponsePath + ".list.length()")).isEqualTo(0); assertThat(jsonPath.parse(response).<Integer>read(firstResponsePath + ".notFound.length()")).isEqualTo(1); } + + @Test + public void getMessagesShouldReturnMandatoryPropertiesMessagesWhenNotAsked() throws Exception { + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z"); + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: my test subject\r\n\r\ntestmail".getBytes()), Date.from(dateTime.toInstant()), false, new Flags()); + embeddedElasticSearch.awaitForElasticSearch(); + + String response = given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + username + "|mailbox|1\"], \"properties\": [\"subject\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .content(startsWith("[[\"messages\",")) + .extract() + .asString(); + + String firstResponsePath = "$.[0].[1]"; + String firstMessagePath = firstResponsePath + ".list[0]"; + + assertThat(JsonPath.parse(response).<Integer>read("$.length()")).isEqualTo(1); + assertThat(JsonPath.parse(response).<Integer>read(firstResponsePath + ".list.length()")).isEqualTo(1); + assertThat(JsonPath.parse(response).<String>read(firstMessagePath + ".id")).isEqualTo("usern...@domain.tld|mailbox|1"); + assertThat(JsonPath.parse(response).<String>read(firstMessagePath + ".threadId")).isNotNull(); + assertThat(JsonPath.parse(response).<List<String>>read(firstMessagePath + ".mailboxIds")).isNotEmpty(); + assertThat(JsonPath.parse(response).<String>read(firstMessagePath + ".subject")).isEqualTo("my test subject"); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java index 99ac236..e030d3f 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -35,8 +34,10 @@ import org.apache.james.jmap.model.ClientId; import org.apache.james.jmap.model.GetMessagesRequest; import org.apache.james.jmap.model.GetMessagesResponse; import org.apache.james.jmap.model.Message; +import org.apache.james.jmap.model.MessageHeaderProperty; import org.apache.james.jmap.model.MessageId; import org.apache.james.jmap.model.MessageProperty; +import org.apache.james.jmap.model.Property; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MessageRange; @@ -46,6 +47,7 @@ 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.util.streams.Collectors; import org.javatuples.Pair; import com.fasterxml.jackson.databind.ser.PropertyWriter; @@ -59,6 +61,7 @@ import com.google.common.collect.Sets; public class GetMessagesMethod<Id extends MailboxId> implements Method { + public static final Set<MessageProperty> MANDATORY_PROPERTIES = ImmutableSet.of(MessageProperty.id, MessageProperty.threadId, MessageProperty.mailboxIds); public static final String HEADERS_FILTER = "headersFilter"; private static final Method.Request.Name METHOD_NAME = Method.Request.name("getMessages"); private static final Method.Response.Name RESPONSE_NAME = Method.Response.name("messages"); @@ -90,73 +93,83 @@ public class GetMessagesMethod<Id extends MailboxId> implements Method { Preconditions.checkArgument(request instanceof GetMessagesRequest); GetMessagesRequest getMessagesRequest = (GetMessagesRequest) request; Optional<ImmutableSet<MessageProperty>> requestedProperties = getMessagesRequest.getProperties(); + Optional<ImmutableSet<MessageHeaderProperty>> headerProperties = getMessagesRequest.getHeaderProperties(); return Stream.of(JmapResponse.builder().clientId(clientId) .response(getMessagesResponse(mailboxSession, getMessagesRequest, requestedProperties)) .responseName(RESPONSE_NAME) - .properties(requestedProperties.map(this::handleSpecificProperties)) - .filterProvider(Optional.of(buildFilteringHeadersFilterProvider(requestedProperties))) + .properties(handleSpecificProperties(requestedProperties, headerProperties)) + .filterProvider(Optional.of(buildFilteringHeadersFilterProvider(headerProperties))) .build()); } - private Set<MessageProperty> handleSpecificProperties(Set<MessageProperty> input) { + private Optional<Set<? extends Property>> handleSpecificProperties(Optional<ImmutableSet<MessageProperty>> requestedProperties, Optional<ImmutableSet<MessageHeaderProperty>> headerProperties) { Set<MessageProperty> toAdd = Sets.newHashSet(); Set<MessageProperty> toRemove = Sets.newHashSet(); - ensureContainsId(input, toAdd); - handleBody(input, toAdd, toRemove); - handleHeadersProperties(input, toAdd, toRemove); - return Sets.union(Sets.difference(input, toRemove), toAdd).immutableCopy(); + toAdd.addAll(ensureContainsMandatoryFields(requestedProperties)); + handleBody(requestedProperties, toAdd, toRemove); + handleHeadersProperties(headerProperties, toAdd, toRemove); + ImmutableSet<MessageProperty> resultProperties = Sets.union( + Sets.difference(requestedProperties.isPresent() ? requestedProperties.get() : ImmutableSet.of(), toRemove) + , toAdd) + .immutableCopy(); + if (resultProperties.isEmpty()) { + return Optional.empty(); + } + return Optional.of(resultProperties); } - - private void ensureContainsId(Set<MessageProperty> input, Set<MessageProperty> toAdd) { - if (!input.contains(MessageProperty.id)) { - toAdd.add(MessageProperty.id); + + private void handleHeadersProperties(Optional<ImmutableSet<MessageHeaderProperty>> headerProperties, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) { + if (headerProperties.isPresent() && !headerProperties.get().isEmpty()) { + toAdd.add(MessageProperty.headers); } } - - private void handleBody(Set<MessageProperty> input, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) { - if (input.contains(MessageProperty.body)) { + + private Set<MessageProperty> ensureContainsMandatoryFields(Optional<ImmutableSet<MessageProperty>> requestedProperties) { + return MANDATORY_PROPERTIES.stream() + .filter(mandatoryProperty -> propertyToAdd(mandatoryProperty, requestedProperties)) + .collect(Collectors.toImmutableSet()); + } + + private boolean propertyToAdd(MessageProperty property, Optional<ImmutableSet<MessageProperty>> requestedProperties) { + return requestedProperties.isPresent() && + !requestedProperties + .filter(properties -> properties.contains(property)) + .flatMap(Optional::of) + .isPresent(); + } + + private void handleBody(Optional<ImmutableSet<MessageProperty>> requestedProperties, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) { + if (requestedProperties.isPresent() && requestedProperties.get().contains(MessageProperty.body)) { toAdd.add(MessageProperty.textBody); toRemove.add(MessageProperty.body); } } - - private void handleHeadersProperties(Set<MessageProperty> input, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) { - Set<MessageProperty> selectHeadersProperties = MessageProperty.selectHeadersProperties(input); - if (!selectHeadersProperties.isEmpty()) { - toAdd.add(MessageProperty.headers); - toRemove.addAll(selectHeadersProperties); - } - } - - private SimpleFilterProvider buildFilteringHeadersFilterProvider(Optional<ImmutableSet<MessageProperty>> requestedProperties) { - Set<MessageProperty> selectedHeadersProperties = requestedProperties - .map(MessageProperty::selectHeadersProperties) - .orElse(ImmutableSet.of()); + private SimpleFilterProvider buildFilteringHeadersFilterProvider(Optional<ImmutableSet<MessageHeaderProperty>> headerProperties) { return new SimpleFilterProvider() - .addFilter(HEADERS_FILTER, buildPropertyFilter(selectedHeadersProperties)) + .addFilter(HEADERS_FILTER, buildPropertyFilter(headerProperties)) .addFilter(JmapResponseWriterImpl.PROPERTIES_FILTER, SimpleBeanPropertyFilter.serializeAll()); } - private SimpleBeanPropertyFilter buildPropertyFilter(Set<MessageProperty> propertiesToInclude) { - if (propertiesToInclude.isEmpty()) { + private SimpleBeanPropertyFilter buildPropertyFilter(Optional<ImmutableSet<MessageHeaderProperty>> headerProperties) { + if (!headerProperties.isPresent()) { return SimpleBeanPropertyFilter.serializeAll(); } else { - return new IncludeMessagePropertyPropertyFilter(propertiesToInclude); + return new IncludeMessagePropertyPropertyFilter(headerProperties.get()); } } private static class IncludeMessagePropertyPropertyFilter extends SimpleBeanPropertyFilter { - private final Set<MessageProperty> propertiesToInclude; + private final Set<MessageHeaderProperty> propertiesToInclude; - public IncludeMessagePropertyPropertyFilter(Set<MessageProperty> propertiesToInclude) { + public IncludeMessagePropertyPropertyFilter(Set<MessageHeaderProperty> propertiesToInclude) { this.propertiesToInclude = propertiesToInclude; } @Override protected boolean include(PropertyWriter writer) { String currentProperty = writer.getName(); - return propertiesToInclude.contains(MessageProperty.headerValueOf(currentProperty)); + return propertiesToInclude.contains(MessageHeaderProperty.fromField(currentProperty)); } } @@ -169,7 +182,7 @@ public class GetMessagesMethod<Id extends MailboxId> implements Method { List<Message> result = getMessagesRequest.getIds().stream() .flatMap(loadMessages) .map(convertToJmapMessage) - .collect(Collectors.toList()); + .collect(Collectors.toImmutableList()); return GetMessagesResponse.builder().messages(result).expectedMessageIds(getMessagesRequest.getIds()).build(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java index bc2f268..708dc3d 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java @@ -19,14 +19,16 @@ package org.apache.james.jmap.model; import java.util.Arrays; +import java.util.List; import java.util.Optional; -import com.google.common.collect.ImmutableSet; import org.apache.james.jmap.methods.JmapRequest; +import org.apache.james.util.streams.Collectors; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; @JsonDeserialize(builder = GetMessagesRequest.Builder.class) public class GetMessagesRequest implements JmapRequest { @@ -40,12 +42,12 @@ public class GetMessagesRequest implements JmapRequest { private Optional<String> accountId; private final ImmutableList.Builder<MessageId> ids; - private Optional<ImmutableSet<MessageProperty>> properties; + private ImmutableSet.Builder<String> propertiesBuilder; private Builder() { accountId = Optional.empty(); ids = ImmutableList.builder(); - properties = Optional.empty(); + propertiesBuilder = null; } public Builder accountId(String accountId) { @@ -58,24 +60,60 @@ public class GetMessagesRequest implements JmapRequest { return this; } - public Builder properties(MessageProperty... properties) { - this.properties = Optional.of(ImmutableSet.copyOf(properties)); + public Builder properties(List<String> properties) { + if (propertiesBuilder == null) { + propertiesBuilder = ImmutableSet.builder(); + } + this.propertiesBuilder.addAll(properties); return this; } public GetMessagesRequest build() { - return new GetMessagesRequest(accountId, ids.build(), properties); + return new GetMessagesRequest(accountId, ids.build(), messageProperties(propertiesBuilder), messageHeaderProperties(propertiesBuilder)); + } + + private Optional<ImmutableSet<MessageProperty>> messageProperties(ImmutableSet.Builder<String> messageProperties) { + if (messageProperties == null) { + return Optional.empty(); + } + return toOptional(messageProperties.build().stream() + .filter(property -> !isHeaderProperty(property)) + .map(MessageProperty::valueOf) + .collect(Collectors.toImmutableSet()), + MessageProperty.class); + } + + private Optional<ImmutableSet<MessageHeaderProperty>> messageHeaderProperties(ImmutableSet.Builder<String> headerProperties) { + if (headerProperties == null) { + return Optional.empty(); + } + return toOptional(headerProperties.build().stream() + .filter(this::isHeaderProperty) + .map(MessageHeaderProperty::valueOf) + .collect(Collectors.toImmutableSet()), + MessageHeaderProperty.class); + } + + private boolean isHeaderProperty(String property) { + return property.startsWith(MessageHeaderProperty.HEADER_PROPERTY_PREFIX); + } + + private <T extends Property> Optional<ImmutableSet<T>> toOptional(ImmutableSet<T> set, Class<T> clazz) { + return Optional.of(set); } } private final Optional<String> accountId; private final ImmutableList<MessageId> ids; private final Optional<ImmutableSet<MessageProperty>> properties; + private final Optional<ImmutableSet<MessageHeaderProperty>> headerProperties; - public GetMessagesRequest(Optional<String> accountId, ImmutableList<MessageId> ids, Optional<ImmutableSet<MessageProperty>> properties) { + public GetMessagesRequest(Optional<String> accountId, ImmutableList<MessageId> ids, + Optional<ImmutableSet<MessageProperty>> properties, Optional<ImmutableSet<MessageHeaderProperty>> headerProperties) { this.accountId = accountId; this.ids = ids; this.properties = properties; + this.headerProperties = headerProperties; } public Optional<String> getAccountId() { @@ -89,4 +127,8 @@ public class GetMessagesRequest implements JmapRequest { public Optional<ImmutableSet<MessageProperty>> getProperties() { return properties; } + + public Optional<ImmutableSet<MessageHeaderProperty>> getHeaderProperties() { + return headerProperties; + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java new file mode 100644 index 0000000..4a51415 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java @@ -0,0 +1,69 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ +package org.apache.james.jmap.model; + +import java.util.Locale; +import java.util.Objects; + +public class MessageHeaderProperty implements Property { + + public static final String HEADER_PROPERTY_PREFIX = "headers."; + + public static MessageHeaderProperty from(MessageProperty messageProperty) { + return new MessageHeaderProperty(HEADER_PROPERTY_PREFIX + messageProperty.asFieldName().toLowerCase(Locale.US)); + } + + public static MessageHeaderProperty fromField(String field) { + return new MessageHeaderProperty(HEADER_PROPERTY_PREFIX + field.toLowerCase(Locale.US)); + } + + public static MessageHeaderProperty valueOf(String property) { + return new MessageHeaderProperty(property.toLowerCase(Locale.US)); + } + + private String property; + + private MessageHeaderProperty(String property) { + this.property = property; + } + + @Override + public String asFieldName() { + return property; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MessageHeaderProperty) { + MessageHeaderProperty other = (MessageHeaderProperty) obj; + return Objects.equals(this.property, other.property); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(property); + } + + @Override + public String toString() { + return Objects.toString(property); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java index 86bd008..df898eb 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java @@ -18,15 +18,12 @@ ****************************************************************/ package org.apache.james.jmap.model; -import java.util.Locale; import java.util.Objects; -import java.util.Set; - -import org.apache.james.util.streams.Collectors; import com.google.common.base.Preconditions; public class MessageProperty implements Property { + public static MessageProperty id = valueOf("id"); public static MessageProperty blobId = valueOf("blobId"); public static MessageProperty threadId = valueOf("threadId"); @@ -52,39 +49,23 @@ public class MessageProperty implements Property { public static MessageProperty attachments = valueOf("attachments"); public static MessageProperty attachedMessages = valueOf("attachedMessages"); public static MessageProperty body = valueOf("body"); - - private static final String HEADER_PROPERTY_PREFIX = "headers."; - + private final String property; - + private MessageProperty(String property) { - this.property = property.toLowerCase(Locale.US); + this.property = property; } public static MessageProperty valueOf(String property) { + Preconditions.checkNotNull(property); return new MessageProperty(property); } - - public static MessageProperty headerValueOf(String headerProperty) { - Preconditions.checkNotNull(headerProperty); - return new MessageProperty(HEADER_PROPERTY_PREFIX + headerProperty); - } - - public static Set<MessageProperty> selectHeadersProperties(Set<MessageProperty> properties) { - return properties.stream() - .filter(MessageProperty::isHeaderProperty) - .collect(Collectors.toImmutableSet()); - } @Override public String asFieldName() { return property; } - - public boolean isHeaderProperty() { - return property.startsWith(HEADER_PROPERTY_PREFIX); - } - + @Override public boolean equals(Object obj) { if (obj instanceof MessageProperty) { @@ -93,12 +74,12 @@ public class MessageProperty implements Property { } return false; } - + @Override public int hashCode() { return Objects.hash(property); } - + @Override public String toString() { return Objects.toString(property); http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java index 67bdbce..5974697 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.NotImplementedException; @@ -58,6 +59,7 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; import com.jayway.jsonpath.JsonPath; public class GetMessagesMethodTest { @@ -176,7 +178,7 @@ public class GetMessagesMethodTest { } @Test - public void processShouldReturnOnlyMessageIdsOnEmptyPropertyList() throws MailboxException { + public void processShouldReturnOnlyMandatoryPropertiesOnEmptyPropertyList() 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)); @@ -184,7 +186,7 @@ public class GetMessagesMethodTest { GetMessagesRequest request = GetMessagesRequest.builder() .ids(new MessageId(ROBERT, inboxPath, message1Uid)) - .properties(new MessageProperty[0]) + .properties(ImmutableList.of()) .build(); GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); @@ -194,11 +196,11 @@ public class GetMessagesMethodTest { .extracting(JmapResponse::getProperties) .flatExtracting(Optional::get) .asList() - .containsOnly(MessageProperty.id); + .containsOnly(MessageProperty.id, MessageProperty.threadId, MessageProperty.mailboxIds); } @Test - public void processShouldReturnIdWhenNotInPropertyList() throws MailboxException { + public void processShouldReturnAllPropertiesWhenNoPropertyGiven() 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)); @@ -206,17 +208,37 @@ public class GetMessagesMethodTest { GetMessagesRequest request = GetMessagesRequest.builder() .ids(new MessageId(ROBERT, inboxPath, message1Uid)) - .properties(MessageProperty.subject) .build(); GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList()); + assertThat(result).hasSize(1); + assertThat(result.get(0).getProperties()).isEmpty(); + } + + @Test + public void processShouldAddMantoryPropertiesWhenNotInPropertyList() 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(ImmutableList.of(MessageProperty.subject.asFieldName())) + .build(); + + Set<MessageProperty> expected = Sets.newHashSet(MessageProperty.id, MessageProperty.threadId, MessageProperty.mailboxIds, MessageProperty.subject); + + GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); + List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList()); + assertThat(result).hasSize(1) .extracting(JmapResponse::getProperties) .flatExtracting(Optional::get) .asList() - .containsOnly(MessageProperty.id, MessageProperty.subject); + .containsOnlyElementsOf(expected); } @Test @@ -228,9 +250,11 @@ public class GetMessagesMethodTest { GetMessagesRequest request = GetMessagesRequest.builder() .ids(new MessageId(ROBERT, inboxPath, message1Uid)) - .properties(MessageProperty.body) + .properties(ImmutableList.of(MessageProperty.body.asFieldName())) .build(); + Set<MessageProperty> expected = Sets.newHashSet(MessageProperty.id, MessageProperty.threadId, MessageProperty.mailboxIds, MessageProperty.textBody); + GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList()); @@ -238,7 +262,7 @@ public class GetMessagesMethodTest { .extracting(JmapResponse::getProperties) .flatExtracting(Optional::get) .asList() - .containsOnly(MessageProperty.id, MessageProperty.textBody); + .containsOnlyElementsOf(expected); } @Test @@ -253,9 +277,11 @@ public class GetMessagesMethodTest { GetMessagesRequest request = GetMessagesRequest.builder() .ids(new MessageId(ROBERT, inboxPath, message1Uid)) - .properties(MessageProperty.valueOf("headers.from"), MessageProperty.valueOf("headers.heADER2")) + .properties(ImmutableList.of("headers.from", "headers.heADER2")) .build(); + Set<MessageProperty> expected = Sets.newHashSet(MessageProperty.id, MessageProperty.threadId, MessageProperty.mailboxIds, MessageProperty.headers); + GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList()); @@ -264,7 +290,7 @@ public class GetMessagesMethodTest { .extracting(JmapResponse::getProperties) .flatExtracting(Optional::get) .asList() - .containsOnly(MessageProperty.id, MessageProperty.headers); + .containsOnlyElementsOf(expected); } @Test @@ -279,7 +305,7 @@ public class GetMessagesMethodTest { GetMessagesRequest request = GetMessagesRequest.builder() .ids(new MessageId(ROBERT, inboxPath, message1Uid)) - .properties(MessageProperty.valueOf("headers.from"), MessageProperty.valueOf("headers.heADER2")) + .properties(ImmutableList.of("headers.from", "headers.heADER2")) .build(); GetMessagesMethod<InMemoryId> testee = new GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory); http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMailboxesRequestTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMailboxesRequestTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMailboxesRequestTest.java index ffa84ac..6a5dc8a 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMailboxesRequestTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMailboxesRequestTest.java @@ -19,6 +19,8 @@ package org.apache.james.jmap.model; +import static org.assertj.core.api.Assertions.assertThat; + import org.apache.commons.lang.NotImplementedException; import org.junit.Test; @@ -36,4 +38,29 @@ public class GetMailboxesRequestTest { GetMailboxesRequest.builder().ids(ImmutableList.of()); } + @Test + public void propertiesShouldBeEmptyWhenNotGiven() { + GetMailboxesRequest getMailboxesRequest = GetMailboxesRequest.builder().build(); + assertThat(getMailboxesRequest.getProperties()).isEmpty(); + } + + @Test + public void propertiesShouldNotBeEmptyWhenEmptyListGiven() { + GetMailboxesRequest getMailboxesRequest = GetMailboxesRequest.builder() + .properties(ImmutableList.of()) + .build(); + + assertThat(getMailboxesRequest.getProperties()).isPresent(); + assertThat(getMailboxesRequest.getProperties().get()).isEmpty();; + } + + @Test + public void propertiesShouldNotBeEmptyWhenListGiven() { + GetMailboxesRequest getMailboxesRequest = GetMailboxesRequest.builder() + .properties(ImmutableList.of("id")) + .build(); + + assertThat(getMailboxesRequest.getProperties()).isPresent(); + assertThat(getMailboxesRequest.getProperties().get()).containsOnly(MailboxProperty.ID); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java index 29bb593..8cecead 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java @@ -23,40 +23,68 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.Test; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; public class GetMessagesRequestTest { @Test public void shouldAllowOptionalAccountId() { - GetMessagesRequest result = GetMessagesRequest.builder().ids(MessageId.of("user|inbox|1")).properties(MessageProperty.id).build(); + GetMessagesRequest result = GetMessagesRequest.builder() + .ids(MessageId.of("user|inbox|1")) + .build(); assertThat(result).isNotNull(); assertThat(result.getAccountId()).isEmpty(); } @Test public void shouldThrowWhenAccountIdIsNull() { - assertThatThrownBy(() -> GetMessagesRequest.builder().accountId(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> GetMessagesRequest.builder().accountId(null)) + .isInstanceOf(NullPointerException.class); } @Test public void shouldAllowEmptyMessagesList() { - GetMessagesRequest result = GetMessagesRequest.builder().accountId("accountId").ids().properties(MessageProperty.id).build(); + GetMessagesRequest result = GetMessagesRequest.builder() + .accountId("accountId") + .ids() + .build(); assertThat(result).isNotNull(); assertThat(result.getIds()).isEmpty(); } @Test public void shouldAllowAbsentPropertyList() { - GetMessagesRequest result = GetMessagesRequest.builder().accountId("accountId").ids().build(); + GetMessagesRequest result = GetMessagesRequest.builder() + .accountId("accountId") + .ids() + .build(); assertThat(result).isNotNull(); assertThat(result.getProperties()).isEmpty(); + assertThat(result.getHeaderProperties()).isEmpty(); } @Test public void shouldAllowEmptyPropertyList() { - GetMessagesRequest result = GetMessagesRequest.builder().accountId("accountId").ids().properties(new MessageProperty[0]).build(); + GetMessagesRequest result = GetMessagesRequest.builder() + .accountId("accountId") + .ids() + .properties(ImmutableList.of()) + .build(); assertThat(result).isNotNull(); - assertThat(result.getProperties()).contains(ImmutableSet.of()); + assertThat(result.getProperties()).isPresent(); + assertThat(result.getHeaderProperties()).isPresent(); + } + + @Test + public void shouldConvertPropertiesWhenMessageAndHeaderPropertiesAreGiven() { + GetMessagesRequest result = GetMessagesRequest.builder() + .accountId("accountId") + .ids() + .properties(ImmutableList.of("id", "headers.subject", "threadId", "headers.test")) + .build(); + assertThat(result).isNotNull(); + assertThat(result.getProperties()).contains(ImmutableSet.of(MessageProperty.id, MessageProperty.threadId)); + assertThat(result.getHeaderProperties()).contains(ImmutableSet.of(MessageHeaderProperty.valueOf("headers.subject"), MessageHeaderProperty.valueOf("headers.test"))); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java new file mode 100644 index 0000000..1c2860e --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java @@ -0,0 +1,58 @@ +/**************************************************************** + * 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.model; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class MessageHeaderPropertyTest { + + @Test(expected=NullPointerException.class) + public void valueOfShouldThrowWhenNull() { + MessageHeaderProperty.valueOf(null); + } + + @Test(expected=NullPointerException.class) + public void valueOfalueOfShouldThrowWhenNull() { + MessageHeaderProperty.valueOf(null); + } + + @Test + public void valueOfShouldReturnLowerCasedProperty() { + MessageHeaderProperty headerProperty = MessageHeaderProperty.valueOf("ProP"); + + assertThat(headerProperty.asFieldName()).isEqualTo("prop"); + } + + @Test + public void equalsShouldBeTrueWhenIdenticalProperties() { + assertThat(MessageHeaderProperty.valueOf("prop")).isEqualTo(MessageHeaderProperty.valueOf("prop")); + } + + @Test + public void equalsShouldBeFalseWhenDifferentProperties() { + assertThat(MessageHeaderProperty.valueOf("prop")).isNotEqualTo(MessageHeaderProperty.valueOf("other")); + } + + @Test + public void equalsShouldBeTrueWhenDifferentCaseProperties() { + assertThat(MessageHeaderProperty.valueOf("prOP")).isEqualTo(MessageHeaderProperty.valueOf("PRop")); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/7dfe3e55/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java index 8368691..37a874e 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java @@ -20,12 +20,8 @@ package org.apache.james.jmap.model; import static org.assertj.core.api.Assertions.assertThat; -import java.util.Set; - import org.junit.Test; -import com.google.common.collect.ImmutableSet; - public class MessagePropertyTest { @Test(expected=NullPointerException.class) @@ -34,48 +30,8 @@ public class MessagePropertyTest { } @Test - public void valueOfThenAsFieldNameShouldReturnLowerCasedProperty() { - assertThat(MessageProperty.valueOf("ProP").asFieldName()).isEqualTo("prop"); - } - - @Test(expected=NullPointerException.class) - public void headerValueOfShouldThrowWhenNull() { - MessageProperty.headerValueOf(null); - } - - @Test - public void headerValueOfShouldReturnPrefixedProperty() { - assertThat(MessageProperty.headerValueOf("Prop").asFieldName()).isEqualTo("headers.prop"); - } - - @Test - public void isHeaderPropertyShouldReturnFalseWhenNotPrefixed() { - assertThat(MessageProperty.valueOf("prop").isHeaderProperty()).isFalse(); - } - - @Test - public void isHeaderPropertyShouldReturnFalseWhenPrefixedBySomethingElse() { - assertThat(MessageProperty.valueOf("somethingelse.prop").isHeaderProperty()).isFalse(); - } - - @Test - public void isHeaderPropertyShouldReturnTrueWhenPrefixedByHeaders() { - assertThat(MessageProperty.valueOf("headers.prop").isHeaderProperty()).isTrue(); - } - - @Test(expected=NullPointerException.class) - public void selectHeadersPropertiesShouldThrowWhenNull() { - MessageProperty.selectHeadersProperties(null); - } - - @Test - public void selectHeadersPropertiesShouldReturnOnlyHeadersProperties() { - Set<MessageProperty> properties = ImmutableSet.of( - MessageProperty.from, - MessageProperty.valueOf("headers.prop"), - MessageProperty.valueOf("headers.prop2"), - MessageProperty.valueOf("prop")); - assertThat(MessageProperty.selectHeadersProperties(properties)).containsOnly(MessageProperty.headerValueOf("prop"), MessageProperty.headerValueOf("prop2")); + public void valueOfThenAsFieldNameShouldReturnMatchingCaseProperty() { + assertThat(MessageProperty.valueOf("ProP").asFieldName()).isEqualTo("ProP"); } @Test @@ -89,7 +45,7 @@ public class MessagePropertyTest { } @Test - public void equalsShouldBeTrueWhenDifferentCaseProperties() { - assertThat(MessageProperty.valueOf("prOP")).isEqualTo(MessageProperty.valueOf("PRop")); + public void equalsShouldBeFalseWhenDifferentCaseProperties() { + assertThat(MessageProperty.valueOf("prOP")).isNotEqualTo(MessageProperty.valueOf("PRop")); } } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org