You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/07/09 01:51:29 UTC

[james-project] branch master updated (b348a27 -> 0310301)

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from b348a27  JAMES-3295 Integration tests RemoteDeliveryErrorHandlingTest
     new 95ab2ec  JAMES-2982 Improve Username validation error messages
     new 3a9c255  JAMES-3295 RemoteDelivery should attach error code to bounced mails
     new e995a08  JAMES-3265 Fasten fetching all flags
     new b5f6d6d  JAMES-3265 IMAP FETCH reading lastUid and lastModseq should be optional
     new c21904c  Fix default Cassandra LDAP configuration
     new 0310301  JAMES-3300 set useConnectionPool to false by default

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/java/org/apache/james/core/Username.java  |   8 +-
 .../destination/conf/mailetcontainer.xml           |   1 +
 .../org/apache/james/mailbox/MessageManager.java   |   4 +
 .../apache/james/mailbox/MailboxManagerTest.java   |  58 +++++++++++
 .../cassandra/mail/CassandraMessageMapper.java     |   6 ++
 .../james/mailbox/store/StoreMessageManager.java   |   8 ++
 .../james/mailbox/store/mail/MessageMapper.java    |  14 +++
 .../apache/james/imap/api/message/FetchData.java   |  10 ++
 .../james/imap/processor/fetch/FetchProcessor.java |  97 +++++++++++++-----
 .../imap/processor/fetch/FetchResponseBuilder.java |  92 ++++++++++++-----
 .../user/ldap/LdapRepositoryConfiguration.java     |   6 +-
 .../transport/mailets/remote/delivery/Bouncer.java |  13 ++-
 .../mailets/remote/delivery/BouncerTest.java       | 113 +++++++++++++++++++++
 .../james/webadmin/routes/MappingRoutesTest.java   |   2 +-
 .../webadmin/routes/UserMailboxesRoutesTest.java   |   2 +-
 .../service/MailboxesExportRequestToTaskTest.java  |   2 +-
 upgrade-instructions.md                            |  12 +++
 17 files changed, 384 insertions(+), 64 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 02/06: JAMES-3295 RemoteDelivery should attach error code to bounced mails

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 3a9c255dc441b6204060decfb170aeff90a01ba3
Author: LanKhuat <kh...@gmail.com>
AuthorDate: Tue Jul 7 10:40:09 2020 +0700

    JAMES-3295 RemoteDelivery should attach error code to bounced mails
---
 .../transport/mailets/remote/delivery/Bouncer.java |  13 ++-
 .../mailets/remote/delivery/BouncerTest.java       | 113 +++++++++++++++++++++
 2 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
index f2d1d3f..b979cc6 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
@@ -24,6 +24,7 @@ import java.io.StringWriter;
 import java.net.ConnectException;
 import java.net.SocketException;
 import java.net.UnknownHostException;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 import javax.mail.SendFailedException;
@@ -41,6 +42,7 @@ public class Bouncer {
     private static final Logger LOGGER = LoggerFactory.getLogger(Bouncer.class);
 
     public static final AttributeName DELIVERY_ERROR = AttributeName.of("delivery-error");
+    public static final AttributeName DELIVERY_ERROR_CODE = AttributeName.of("delivery-error-code");
     private final RemoteDeliveryConfiguration configuration;
     private final MailetContext mailetContext;
 
@@ -54,6 +56,7 @@ public class Bouncer {
             LOGGER.debug("Null Sender: no bounce will be generated for {}", mail.getName());
         } else {
             if (configuration.getBounceProcessor() != null) {
+                computeErrorCode(ex).ifPresent(mail::setAttribute);
                 mail.setAttribute(new Attribute(DELIVERY_ERROR, AttributeValue.of(getErrorMsg(ex))));
                 try {
                     mailetContext.sendMail(mail, configuration.getBounceProcessor());
@@ -66,6 +69,14 @@ public class Bouncer {
         }
     }
 
+    private Optional<Attribute> computeErrorCode(Exception ex) {
+        return Optional.ofNullable(ex)
+            .filter(e -> e instanceof MessagingException)
+            .map(MessagingException.class::cast)
+            .map(EnhancedMessagingException::new)
+            .flatMap(EnhancedMessagingException::getReturnCode)
+            .map(code -> new Attribute(DELIVERY_ERROR_CODE, AttributeValue.of(code)));
+    }
 
     private void bounceWithMailetContext(Mail mail, Exception ex) {
         LOGGER.debug("Sending failure message {}", mail.getName());
@@ -115,7 +126,7 @@ public class Bouncer {
     }
 
     private String sanitizeExceptionMessage(Exception e) {
-        if (e.getMessage() == null) {
+        if (e == null || e.getMessage() == null) {
             return "null";
         } else {
             return e.getMessage().trim();
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
index 57e93dc..c759b9d 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
@@ -20,8 +20,10 @@
 package org.apache.james.transport.mailets.remote.delivery;
 
 import static org.apache.james.transport.mailets.remote.delivery.Bouncer.DELIVERY_ERROR;
+import static org.apache.james.transport.mailets.remote.delivery.Bouncer.DELIVERY_ERROR_CODE;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.net.ConnectException;
 import java.net.SocketException;
@@ -42,12 +44,15 @@ import org.apache.mailet.base.test.FakeMailetConfig;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.sun.mail.smtp.SMTPSendFailedException;
+
 public class BouncerTest {
     private static final String HELLO_NAME = "hello_name";
     private static final FakeMailetConfig DEFAULT_REMOTE_DELIVERY_CONFIG = FakeMailetConfig.builder()
         .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
         .build();
     private static final String BOUNCE_PROCESSOR = "bounce_processor";
+    public static final int SMTP_ERROR_CODE_521 = 521;
 
     private FakeMailContext mailetContext;
 
@@ -417,4 +422,112 @@ public class BouncerTest {
         assertThat(mailetContext.getSentMails()).containsOnly(expected);
         assertThat(mailetContext.getBouncedMails()).isEmpty();
     }
+
+    @Test
+    public void bounceShouldAttachErrorCodeWhenSmtpError() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        SMTPSendFailedException ex = mock(SMTPSendFailedException.class);
+        when(ex.getReturnCode()).thenReturn(SMTP_ERROR_CODE_521);
+
+        testee.bounce(mail, ex);
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .attribute(new Attribute(DELIVERY_ERROR_CODE, AttributeValue.of(SMTP_ERROR_CODE_521)))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldNotAttachErrorCodeWhenNotMessagingException() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, new Exception());
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldNotAttachErrorCodeWhenNotSmtpError() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, new MessagingException("not smtp related"));
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("not smtp related")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldAttachNullErrorMessageWhenNoException() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, null);
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 01/06: JAMES-2982 Improve Username validation error messages

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 95ab2ec6852b23a6e3dc5754122b1f86eff926cb
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Jul 7 09:00:56 2020 +0700

    JAMES-2982 Improve Username validation error messages
    
    Upon bad formats, having the username value helps debugging
---
 core/src/main/java/org/apache/james/core/Username.java            | 8 ++++----
 .../java/org/apache/james/webadmin/routes/MappingRoutesTest.java  | 2 +-
 .../org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java | 2 +-
 .../james/webadmin/service/MailboxesExportRequestToTaskTest.java  | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/core/src/main/java/org/apache/james/core/Username.java b/core/src/main/java/org/apache/james/core/Username.java
index e0c14fa..343f565 100644
--- a/core/src/main/java/org/apache/james/core/Username.java
+++ b/core/src/main/java/org/apache/james/core/Username.java
@@ -36,7 +36,7 @@ public class Username {
 
     public static Username of(String username) {
         Preconditions.checkArgument(username != null, "username should not be null or empty");
-        Preconditions.checkArgument(!username.trim().isEmpty(), "username should not be null or empty");
+        Preconditions.checkArgument(!username.trim().isEmpty(), "username should not be null or empty after being trimmed");
         Preconditions.checkArgument(username.length() <= MAXIMUM_MAIL_ADDRESS_LENGTH,
             "username length should not be longer than %s characters", MAXIMUM_MAIL_ADDRESS_LENGTH);
 
@@ -47,7 +47,7 @@ public class Username {
             case 2:
                 return fromLocalPartWithDomain(parts.get(0), parts.get(1));
         }
-        throw new IllegalArgumentException("The username should not contain multiple domain delimiter.");
+        throw new IllegalArgumentException("The username should not contain multiple domain delimiter. Value: " + username);
     }
 
     public static Username fromLocalPartWithDomain(String localPart, String domain) {
@@ -82,8 +82,8 @@ public class Username {
 
     private Username(String localPart, Optional<Domain> domainPart) {
         Preconditions.checkNotNull(localPart);
-        Preconditions.checkArgument(!localPart.isEmpty(), "username should not be empty");
-        Preconditions.checkArgument(!localPart.contains("@"), "username can not contain domain delimiter");
+        Preconditions.checkArgument(!localPart.isEmpty(), "username local part should not be empty");
+        Preconditions.checkArgument(!localPart.contains("@"), "username local part can not contain domain delimiter, got %s", localPart);
 
         this.localPart = localPart.toLowerCase(Locale.US);
         this.domainPart = domainPart;
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/MappingRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/MappingRoutesTest.java
index 01fb052..588cc1d 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/MappingRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/MappingRoutesTest.java
@@ -588,7 +588,7 @@ class MappingRoutesTest {
         .body("statusCode", is(400))
         .body("type", is("InvalidArgument"))
         .body("message", is("Invalid arguments supplied in the user request"))
-        .body("details", is("The username should not contain multiple domain delimiter."));
+        .body("details", is("The username should not contain multiple domain delimiter. Value: alice123@domain@domain.tld"));
     }
 
     @Test
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
index f6db1b5..169d76f 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
@@ -1239,7 +1239,7 @@ class UserMailboxesRoutesTest {
                     .body("statusCode", Matchers.is(400))
                     .body("type", Matchers.is("InvalidArgument"))
                     .body("message", Matchers.is("Invalid arguments supplied in the user request"))
-                    .body("details", Matchers.is("The username should not contain multiple domain delimiter."));
+                    .body("details", Matchers.is("The username should not contain multiple domain delimiter. Value: bad@bad@bad"));
             }
         }
 
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java
index e518170..d2570c7 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java
@@ -180,7 +180,7 @@ class MailboxesExportRequestToTaskTest {
             .body("statusCode", is(400))
             .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
             .body("message", is("Invalid arguments supplied in the user request"))
-            .body("details", is("The username should not contain multiple domain delimiter."));
+            .body("details", is("The username should not contain multiple domain delimiter. Value: bad@bad@bad"));
     }
 
     @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 03/06: JAMES-3265 Fasten fetching all flags

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit e995a086616d3c29722490451700c3c4c89b2392
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Jul 7 14:28:39 2020 +0700

    JAMES-3265 Fasten fetching all flags
    
    As we disabled buggy CONDSTORE extension upon reconnection, TBird has no
    choice than to do a full scan of all uid & flags to resync.
    
    This operation is costly.
    
    On top of the Cassandra backend, 99+% of the time is spent reading the
    messagev2 table that is not needed for this Fetch request, effectively
    slowing down the request.
    
    By adding a method allowing to retrieve ComposedMessageIdWithMetaDatas for
    a range in a given mailbox on top of the MessageManager, we allow
    significant performance enhancement for IMAP on top of the Cassandra backend.
---
 .../org/apache/james/mailbox/MessageManager.java   |  4 +
 .../apache/james/mailbox/MailboxManagerTest.java   | 58 ++++++++++++++
 .../cassandra/mail/CassandraMessageMapper.java     |  6 ++
 .../james/mailbox/store/StoreMessageManager.java   |  8 ++
 .../james/mailbox/store/mail/MessageMapper.java    | 14 ++++
 .../apache/james/imap/api/message/FetchData.java   | 10 +++
 .../james/imap/processor/fetch/FetchProcessor.java | 86 ++++++++++++++------
 .../imap/processor/fetch/FetchResponseBuilder.java | 92 ++++++++++++++++------
 8 files changed, 228 insertions(+), 50 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
index 6c21579..88c0476 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
@@ -39,6 +39,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.UnsupportedCriteriaException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxACL;
@@ -53,6 +54,7 @@ import org.apache.james.mailbox.model.SearchQuery;
 import org.apache.james.mailbox.model.UidValidity;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.mime4j.message.DefaultMessageWriter;
+import org.reactivestreams.Publisher;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -321,6 +323,8 @@ public interface MessageManager {
      */
     MessageResultIterator getMessages(MessageRange set, FetchGroup fetchGroup, MailboxSession mailboxSession) throws MailboxException;
 
+    Publisher<ComposedMessageIdWithMetaData> listMessagesMetadata(MessageRange set, MailboxSession session);
+
     /**
      * Return the underlying {@link Mailbox}
      */
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 7a8dbe5..c1692e9 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -19,6 +19,7 @@
 package org.apache.james.mailbox;
 
 import static org.apache.james.mailbox.MailboxManager.RenameOption.RENAME_SUBSCRIPTIONS;
+import static org.apache.james.mailbox.MessageManager.FlagsUpdateMode.REPLACE;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -63,6 +64,7 @@ import org.apache.james.mailbox.exception.TooLongMailboxNameException;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.mock.DataProvisioner;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxAnnotation;
@@ -2665,6 +2667,62 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
         }
 
         @Test
+        void listMessagesMetadataShouldReturnEmptyWhenNoMessages() {
+            assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+                .collectList().block())
+                .isEmpty();
+        }
+
+        @Test
+        void listMessagesMetadataShouldReturnAppendedMessage() throws Exception {
+            Flags flags = new Flags(Flags.Flag.DELETED);
+            ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
+                .withFlags(flags)
+                .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+            assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+                    .collectList().block())
+                .hasSize(1)
+                .allSatisfy(ids -> SoftAssertions.assertSoftly(softly -> {
+                    softly.assertThat(ids.getComposedMessageId().getMailboxId()).isEqualTo(composeId.getMailboxId());
+                    softly.assertThat(ids.getComposedMessageId().getUid()).isEqualTo(composeId.getUid());
+                    softly.assertThat(ids.getFlags()).isEqualTo(flags);
+                }));
+        }
+
+        @Test
+        void listMessagesMetadataShouldReturnUpdatedMessage() throws Exception {
+            Flags flags = new Flags(Flags.Flag.SEEN);
+            ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.DELETED))
+                .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+            inboxManager.setFlags(flags, REPLACE, MessageRange.all(), session);
+
+            assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+                    .collectList().block())
+                .hasSize(1)
+                .allSatisfy(ids -> SoftAssertions.assertSoftly(softly -> {
+                    softly.assertThat(ids.getComposedMessageId().getMailboxId()).isEqualTo(composeId.getMailboxId());
+                    softly.assertThat(ids.getComposedMessageId().getUid()).isEqualTo(composeId.getUid());
+                    softly.assertThat(ids.getFlags()).isEqualTo(flags);
+                }));
+        }
+
+        @Test
+        void listMessagesMetadataShouldNotReturnDeletedMessage() throws Exception {
+            inboxManager.appendMessage(AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.DELETED))
+                .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+            inboxManager.expunge(MessageRange.all(), session);
+
+            assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+                    .collectList().block())
+                .isEmpty();
+        }
+
+        @Test
         void getMessagesShouldIncludeHasAttachmentInformation() throws Exception {
             ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
                 .withFlags(new Flags(Flags.Flag.DELETED))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index fb94eff..75adad6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -172,6 +172,12 @@ public class CassandraMessageMapper implements MessageMapper {
     }
 
     @Override
+    public Flux<ComposedMessageIdWithMetaData> listMessagesMetadata(Mailbox mailbox, MessageRange set) {
+        CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
+        return messageIdDAO.retrieveMessages(mailboxId, set, Limit.unlimited());
+    }
+
+    @Override
     public Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange messageRange, FetchType ftype, int limitAsInt) {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index d4a8c6a..53079f4 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -60,6 +60,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.ReadOnlyException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxACL;
@@ -97,6 +98,7 @@ import org.apache.james.util.IteratorWrapper;
 import org.apache.james.util.io.BodyOffsetInputStream;
 import org.apache.james.util.io.InputStreamConsummer;
 import org.apache.james.util.streams.Iterators;
+import org.reactivestreams.Publisher;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
@@ -651,6 +653,12 @@ public class StoreMessageManager implements MessageManager {
         return new StoreMessageResultIterator(messageMapper, mailbox, set, batchSizes, fetchGroup);
     }
 
+    @Override
+    public Publisher<ComposedMessageIdWithMetaData> listMessagesMetadata(MessageRange set, MailboxSession session) {
+        MessageMapper messageMapper = mapperFactory.getMessageMapper(session);
+        return messageMapper.listMessagesMetadata(mailbox, set);
+    }
+
     /**
      * Return a List which holds all uids of recent messages and optional reset
      * the recent flag on the messages for the uids
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
index d92be02..1d4f6f4 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
@@ -31,6 +31,8 @@ import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxCounters;
 import org.apache.james.mailbox.model.MessageMetaData;
@@ -52,6 +54,7 @@ import reactor.core.publisher.Mono;
  * to the end of the request.
  */
 public interface MessageMapper extends Mapper {
+    int UNLIMITED = -1;
 
     /**
      * Return a {@link Iterator} which holds the messages for the given criterias
@@ -65,6 +68,17 @@ public interface MessageMapper extends Mapper {
     Iterator<MailboxMessage> findInMailbox(Mailbox mailbox, MessageRange set, FetchType type, int limit)
             throws MailboxException;
 
+    default Flux<ComposedMessageIdWithMetaData> listMessagesMetadata(Mailbox mailbox, MessageRange set) {
+        return findInMailboxReactive(mailbox, set, FetchType.Metadata, UNLIMITED)
+            .map(message -> new ComposedMessageIdWithMetaData(
+                new ComposedMessageId(
+                    message.getMailboxId(),
+                    message.getMessageId(),
+                    message.getUid()),
+                message.createFlags(),
+                message.getModSeq()));
+    }
+
     default Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange set, FetchType type, int limit) {
         try {
             return Iterators.toFlux(findInMailbox(mailbox, set, type, limit));
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java b/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
index 3a4b305..822dfa2 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
@@ -142,6 +142,16 @@ public class FetchData {
         return vanished;
     }
 
+    public boolean isOnlyFlags() {
+        return bodyElements.isEmpty()
+            && itemToFetch.stream()
+            .filter(item -> item != Item.FLAGS)
+            .filter(item -> item != Item.UID)
+            .filter(item -> item != Item.MODSEQ)
+            .findAny()
+            .isEmpty();
+    }
+
     @Override
     public final int hashCode() {
         return Objects.hash(itemToFetch, bodyElements, setSeen, changedSince);
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
index 4fe3a81..53cdff2 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
@@ -21,6 +21,7 @@ package org.apache.james.imap.processor.fetch;
 
 import java.io.Closeable;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.james.imap.api.ImapConstants;
@@ -41,6 +42,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageManager.MailboxMetaData;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MessageRangeException;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.MessageResult;
@@ -50,6 +52,8 @@ import org.apache.james.util.MDCBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Flux;
+
 public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
     private static final Logger LOGGER = LoggerFactory.getLogger(FetchProcessor.class);
 
@@ -140,37 +144,71 @@ public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
         FetchGroup resultToFetch = FetchDataConverter.getFetchGroup(fetch);
 
         for (MessageRange range : ranges) {
-            MessageResultIterator messages = mailbox.getMessages(range, resultToFetch, mailboxSession);
-            while (messages.hasNext()) {
-                final MessageResult result = messages.next();
+            if (fetch.isOnlyFlags()) {
+                processMessageRangeForFlags(session, mailbox, fetch, mailboxSession, responder, builder, range);
+            } else {
+                processMessageRange(session, mailbox, fetch, useUids, mailboxSession, responder, builder, resultToFetch, range);
+            }
+        }
 
-                //skip unchanged messages - this should be filtered at the mailbox level to take advantage of indexes
-                if (fetch.contains(Item.MODSEQ) && result.getModSeq().asLong() <= fetch.getChangedSince()) {
-                    continue;
-                }
+    }
 
-                try {
-                    final FetchResponse response = builder.build(fetch, result, mailbox, session, useUids);
-                    responder.respond(response);
-                } catch (MessageRangeException e) {
-                    // we can't for whatever reason find the message so
-                    // just skip it and log it to debug
-                    LOGGER.debug("Unable to find message with uid {}", result.getUid(), e);
-                } catch (MailboxException e) {
-                    // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
-                    // So we just skip it 
-                    //
-                    // See IMAP-347
-                    LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getUid(), e);
-                }
+    private void processMessageRangeForFlags(ImapSession session, MessageManager mailbox, FetchData fetch, MailboxSession mailboxSession, Responder responder, FetchResponseBuilder builder, MessageRange range) {
+        Iterator<ComposedMessageIdWithMetaData> results = Flux.from(mailbox.listMessagesMetadata(range, mailboxSession))
+            .filter(ids -> !fetch.contains(Item.MODSEQ) || ids.getModSeq().asLong() > fetch.getChangedSince())
+            .toStream()
+            .iterator();
+
+        while (results.hasNext()) {
+            ComposedMessageIdWithMetaData result = results.next();
+
+            try {
+                final FetchResponse response = builder.build(fetch, result, mailbox, session);
+                responder.respond(response);
+            } catch (MessageRangeException e) {
+                // we can't for whatever reason find the message so
+                // just skip it and log it to debug
+                LOGGER.debug("Unable to find message with uid {}", result.getComposedMessageId().getUid(), e);
+            } catch (MailboxException e) {
+                // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
+                // So we just skip it
+                //
+                // See IMAP-347
+                LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getComposedMessageId().getUid(), e);
             }
+        }
+    }
+
+    private void processMessageRange(ImapSession session, MessageManager mailbox, FetchData fetch, boolean useUids, MailboxSession mailboxSession, Responder responder, FetchResponseBuilder builder, FetchGroup resultToFetch, MessageRange range) throws MailboxException {
+        MessageResultIterator messages = mailbox.getMessages(range, resultToFetch, mailboxSession);
+        while (messages.hasNext()) {
+            final MessageResult result = messages.next();
 
-            // Throw the exception if we received one
-            if (messages.getException() != null) {
-                throw messages.getException();
+            //skip unchanged messages - this should be filtered at the mailbox level to take advantage of indexes
+            if (fetch.contains(Item.MODSEQ) && result.getModSeq().asLong() <= fetch.getChangedSince()) {
+                continue;
+            }
+
+            try {
+                final FetchResponse response = builder.build(fetch, result, mailbox, session, useUids);
+                responder.respond(response);
+            } catch (MessageRangeException e) {
+                // we can't for whatever reason find the message so
+                // just skip it and log it to debug
+                LOGGER.debug("Unable to find message with uid {}", result.getUid(), e);
+            } catch (MailboxException e) {
+                // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
+                // So we just skip it
+                //
+                // See IMAP-347
+                LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getUid(), e);
             }
         }
 
+        // Throw the exception if we received one
+        if (messages.getException() != null) {
+            throw messages.getException();
+        }
     }
 
 
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
index bc978b7..73f18f7 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MessageRangeException;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.Content;
 import org.apache.james.mailbox.model.Header;
 import org.apache.james.mailbox.model.MessageRange;
@@ -125,21 +126,9 @@ public final class FetchResponseBuilder {
             // message. If so, update the flags, and ensure that a flags response is
             // included in the response.
             final MailboxSession mailboxSession = session.getMailboxSession();
-            boolean ensureFlagsResponse = false;
-            final Flags resultFlags = result.getFlags();
-            if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
-                mailbox.setFlags(new Flags(Flags.Flag.SEEN), MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid), mailboxSession);
-                resultFlags.add(Flags.Flag.SEEN);
-                ensureFlagsResponse = true;
-            }
 
             // FLAGS response
-            if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
-                if (selected.isRecent(resultUid)) {
-                    resultFlags.add(Flags.Flag.RECENT);
-                }
-                setFlags(resultFlags);
-            }
+            addFlags(fetch, mailbox, selected, resultUid, mailboxSession, result.getFlags());
 
             // INTERNALDATE response
             if (fetch.contains(Item.INTERNAL_DATE)) {
@@ -183,23 +172,74 @@ public final class FetchResponseBuilder {
                     bodystructure = new MimeDescriptorStructure(true, result.getMimeDescriptor(), envelopeBuilder);
                 }
             }
-            // UID response
-            if (fetch.contains(Item.UID)) {
-                setUid(resultUid);
-            }
 
+            addUid(fetch, resultUid);
 
-            if (fetch.contains(Item.MODSEQ)) {
-                long changedSince = fetch.getChangedSince();
-                if (changedSince != -1) {
-                    // check if the modsequence if higher then the one specified by the CHANGEDSINCE option
-                    if (changedSince < result.getModSeq().asLong()) {
-                        setModSeq(result.getModSeq());
-                    }
-                } else {
-                    setModSeq(result.getModSeq());
+            addModSeq(fetch, result.getModSeq());
+
+            return build();
+        });
+    }
+
+    private void addUid(FetchData fetch, MessageUid resultUid) {
+        // UID response
+        if (fetch.contains(Item.UID)) {
+            setUid(resultUid);
+        }
+    }
+
+    private void addModSeq(FetchData fetch, ModSeq modSeq) {
+        if (fetch.contains(Item.MODSEQ)) {
+            long changedSince = fetch.getChangedSince();
+            if (changedSince != -1) {
+                // check if the modsequence if higher then the one specified by the CHANGEDSINCE option
+                if (changedSince < modSeq.asLong()) {
+                    setModSeq(modSeq);
                 }
+            } else {
+                setModSeq(modSeq);
+            }
+        }
+    }
+
+    private void addFlags(FetchData fetch, MessageManager mailbox, SelectedMailbox selected, MessageUid resultUid, MailboxSession mailboxSession, Flags flags) throws MailboxException {
+        boolean ensureFlagsResponse = false;
+        final Flags resultFlags = flags;
+        if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
+            mailbox.setFlags(new Flags(Flags.Flag.SEEN), MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid), mailboxSession);
+            resultFlags.add(Flags.Flag.SEEN);
+            ensureFlagsResponse = true;
+        }
+
+        if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
+            if (selected.isRecent(resultUid)) {
+                resultFlags.add(Flags.Flag.RECENT);
             }
+            setFlags(resultFlags);
+        }
+    }
+
+    public FetchResponse build(FetchData fetch, ComposedMessageIdWithMetaData result, MessageManager mailbox, ImapSession session) throws MessageRangeException, MailboxException {
+        final SelectedMailbox selected = session.getSelected();
+        final MessageUid resultUid = result.getComposedMessageId().getUid();
+        return selected.msn(resultUid).fold(() -> {
+            throw new MessageRangeException("No such message found with uid " + resultUid);
+        }, msn -> {
+
+            reset(msn);
+            // setMsn(resultMsn);
+
+            // Check if this fetch will cause the "SEEN" flag to be set on this
+            // message. If so, update the flags, and ensure that a flags response is
+            // included in the response.
+            final MailboxSession mailboxSession = session.getMailboxSession();
+            // FLAGS response
+            addFlags(fetch, mailbox, selected, resultUid, mailboxSession, result.getFlags());
+            // UID response
+            addUid(fetch, resultUid);
+
+
+            addModSeq(fetch, result.getModSeq());
             return build();
         });
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 04/06: JAMES-3265 IMAP FETCH reading lastUid and lastModseq should be optional

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit b5f6d6d3807af60df9dc0e0cceb4ef4ad4e90d33
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jul 8 14:08:29 2020 +0700

    JAMES-3265 IMAP FETCH reading lastUid and lastModseq should be optional
    
    When FETCH is not used with `vanished` or CONDSTORE arguments then the response
    returned to the IMAP clients does not need to include mailbox lastUid & lastModSeq
    metadata.
    
    Upon load, reading these metadata accounts for 5% of the total amount of Cassandra
    query time triggered by the IMAP FETCH workload on top of the Distributed James server,
    leading to a nice but limited performance improvement.
---
 .../org/apache/james/imap/processor/fetch/FetchProcessor.java | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
index 53cdff2..901b472 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
@@ -49,9 +49,12 @@ import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mailbox.model.MessageResultIterator;
 import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.util.MDCBuilder;
+import org.apache.james.util.MemoizedSupplier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.fge.lambdas.Throwing;
+
 import reactor.core.publisher.Flux;
 
 public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
@@ -86,10 +89,12 @@ public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
             }
             final MailboxSession mailboxSession = session.getMailboxSession();
 
-            MailboxMetaData metaData = mailbox.getMetaData(false, mailboxSession, MailboxMetaData.FetchGroup.NO_COUNT);
+            MemoizedSupplier<MailboxMetaData> metaData = MemoizedSupplier.of(Throwing.supplier(
+                    () -> mailbox.getMetaData(false, mailboxSession, MailboxMetaData.FetchGroup.NO_COUNT))
+                .sneakyThrow());
             if (fetch.getChangedSince() != -1 || fetch.contains(Item.MODSEQ)) {
                 // Enable CONDSTORE as this is a CONDSTORE enabling command
-                condstoreEnablingCommand(session, responder,  metaData, true);
+                condstoreEnablingCommand(session, responder,  metaData.get(), true);
             }
             
             List<MessageRange> ranges = new ArrayList<>();
@@ -106,7 +111,7 @@ public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
             if (vanished) {
                 // TODO: From the QRESYNC RFC it seems ok to send the VANISHED responses after the FETCH Responses. 
                 //       If we do so we could prolly save one mailbox access which should give use some more speed up
-                respondVanished(mailboxSession, mailbox, ranges, changedSince, metaData, responder);
+                respondVanished(mailboxSession, mailbox, ranges, changedSince, metaData.get(), responder);
             }
             processMessageRanges(session, mailbox, ranges, fetch, useUids, mailboxSession, responder);
 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 05/06: Fix default Cassandra LDAP configuration

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c21904c516e63c5223f874daf12257fcb90127ad
Author: Raphael Ouazana <ra...@linagora.com>
AuthorDate: Wed Jul 8 09:11:55 2020 +0200

    Fix default Cassandra LDAP configuration
---
 .../run/guice/cassandra-ldap/destination/conf/mailetcontainer.xml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dockerfiles/run/guice/cassandra-ldap/destination/conf/mailetcontainer.xml b/dockerfiles/run/guice/cassandra-ldap/destination/conf/mailetcontainer.xml
index 38a5ede..d66b290 100644
--- a/dockerfiles/run/guice/cassandra-ldap/destination/conf/mailetcontainer.xml
+++ b/dockerfiles/run/guice/cassandra-ldap/destination/conf/mailetcontainer.xml
@@ -71,6 +71,7 @@
             <mailet match="RecipientIsLocal" class="org.apache.james.jmap.mailet.VacationMailet"/>
             <mailet match="RecipientIsLocal" class="Sieve"/>
             <mailet match="RecipientIsLocal" class="AddDeliveredToHeader"/>
+            <mailet match="RecipientIsLocal" class="org.apache.james.jmap.mailet.filter.JMAPFiltering"/>
             <mailet match="RecipientIsLocal" class="LocalDelivery"/>
             <mailet match="HostIsLocal" class="ToProcessor">
                 <processor>local-address-error</processor>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 06/06: JAMES-3300 set useConnectionPool to false by default

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 03103018aefc1885f479b01f7df7c31e0d42e682
Author: Raphael Ouazana <ra...@linagora.com>
AuthorDate: Wed Jul 8 10:32:50 2020 +0200

    JAMES-3300 set useConnectionPool to false by default
---
 .../apache/james/user/ldap/LdapRepositoryConfiguration.java  |  6 +++---
 upgrade-instructions.md                                      | 12 ++++++++++++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
index 127fe02..f526cd2 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
@@ -32,7 +32,7 @@ import com.google.common.base.Preconditions;
 public class LdapRepositoryConfiguration {
     public static final String SUPPORTS_VIRTUAL_HOSTING = "supportsVirtualHosting";
 
-    private static final boolean USE_CONNECTION_POOL = true;
+    private static final boolean NO_CONNECTION_POOL = false;
     private static final int NO_CONNECTION_TIMEOUT = -1;
     private static final int NO_READ_TIME_OUT = -1;
     private static final boolean ENABLE_VIRTUAL_HOSTING = true;
@@ -134,7 +134,7 @@ public class LdapRepositoryConfiguration {
                 userBase.get(),
                 userIdAttribute.get(),
                 userObjectClass.get(),
-                USE_CONNECTION_POOL,
+                NO_CONNECTION_POOL,
                 NO_CONNECTION_TIMEOUT,
                 NO_READ_TIME_OUT,
                 maxRetries.get(),
@@ -160,7 +160,7 @@ public class LdapRepositoryConfiguration {
         String userIdAttribute = configuration.getString("[@userIdAttribute]");
         String userObjectClass = configuration.getString("[@userObjectClass]");
         // Default is to use connection pooling
-        boolean useConnectionPool = configuration.getBoolean("[@useConnectionPool]", USE_CONNECTION_POOL);
+        boolean useConnectionPool = configuration.getBoolean("[@useConnectionPool]", NO_CONNECTION_POOL);
         int connectionTimeout = configuration.getInt("[@connectionTimeout]", NO_CONNECTION_TIMEOUT);
         int readTimeout = configuration.getInt("[@readTimeout]", NO_READ_TIME_OUT);
         // Default maximum retries is 1, which allows an alternate connection to
diff --git a/upgrade-instructions.md b/upgrade-instructions.md
index a1171f4..6857221 100644
--- a/upgrade-instructions.md
+++ b/upgrade-instructions.md
@@ -35,6 +35,18 @@ Change list:
  - [Log4J2 Adoption](#log4j2-adoption)
  - [Drop Cassandra schema version prior version 5](#drop-cassandra-schema-version-prior-version-5)
  - [mailqueue.size.metricsEnabled now defaults to false](#mailqueuesizemetricsenabled-now-defaults-to-false)
+ - [LDAP users repository connection pool now defaults to false](#ldap-users-repository-connection-pool-now-defaults-to-false)
+
+### LDAP users repository connection pool now defaults to false
+
+Date 08/07/2020
+
+JIRA: https://issues.apache.org/jira/browse/JAMES-3300
+
+Concerned product: all products relying on LDAP users repository
+
+`useConnectionPool` is now false by default. If you really want it, you have to explicitely put it to `true` in `usersrepository.xml`.
+It is false by default because it can create too much connections on the LDAP server. If you have few users it can eventually still make sense.
 
 ### mailqueue.size.metricsEnabled now defaults to false
 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org