You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/01/19 03:21:54 UTC

[james-project] 01/03: JAMES-3867 Allow IMAP extensions configuration

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 e1377cdc6fc9c0a419d290bf6b85cfa3e127a2e7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jan 16 10:51:07 2023 +0700

    JAMES-3867 Allow IMAP extensions configuration
    
    One can define custom, per-IMAP server
    configuration values.
---
 .../apache/james/examples/imap/PingProcessor.java  | 16 +++++++++++++--
 .../custom-imap/src/main/resources/imapserver.xml  | 15 ++------------
 .../examples/imap/ImapCustomPackagesTest.java      |  9 ++++++++-
 .../apache/james/imap/api/ImapConfiguration.java   | 23 +++++++++++++++++++---
 .../apache/james/imapserver/netty/IMAPServer.java  |  1 +
 .../netty/IMAPServerConfigurationTest.java         |  7 +++++++
 6 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/examples/custom-imap/src/main/java/org/apache/james/examples/imap/PingProcessor.java b/examples/custom-imap/src/main/java/org/apache/james/examples/imap/PingProcessor.java
index a308295870..fe26a5c6a3 100644
--- a/examples/custom-imap/src/main/java/org/apache/james/examples/imap/PingProcessor.java
+++ b/examples/custom-imap/src/main/java/org/apache/james/examples/imap/PingProcessor.java
@@ -19,8 +19,11 @@
 
 package org.apache.james.examples.imap;
 
+import java.util.Properties;
+
 import javax.inject.Inject;
 
+import org.apache.james.imap.api.ImapConfiguration;
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.process.ImapSession;
@@ -30,8 +33,8 @@ import org.apache.james.util.MDCBuilder;
 import reactor.core.publisher.Mono;
 
 public class PingProcessor extends AbstractProcessor<PingImapPackages.PingRequest> {
-
     private final StatusResponseFactory factory;
+    private String pongResponse;
 
     @Inject
     public PingProcessor(StatusResponseFactory factory) {
@@ -39,10 +42,19 @@ public class PingProcessor extends AbstractProcessor<PingImapPackages.PingReques
         this.factory = factory;
     }
 
+    @Override
+    public void configure(ImapConfiguration imapConfiguration) {
+        Properties customProperties = imapConfiguration.getCustomProperties();
+
+        pongResponse = (String) customProperties
+            .getOrDefault("pong.response", "completed.");
+    }
+
     @Override
     protected Mono<Void> doProcess(PingImapPackages.PingRequest request, Responder responder, ImapSession session) {
         return Mono.fromRunnable(() -> responder.respond(new PingImapPackages.PingResponse()))
-            .then(Mono.fromRunnable(() -> responder.respond(factory.taggedOk(request.getTag(), request.getCommand(), HumanReadableText.COMPLETED))));
+            .then(Mono.fromRunnable(() -> responder.respond(
+                factory.taggedOk(request.getTag(), request.getCommand(), new HumanReadableText("org.apache.james.imap.COMPLETED", pongResponse)))));
     }
 
     @Override
diff --git a/examples/custom-imap/src/main/resources/imapserver.xml b/examples/custom-imap/src/main/resources/imapserver.xml
index c9eff82382..a6c9d42c66 100644
--- a/examples/custom-imap/src/main/resources/imapserver.xml
+++ b/examples/custom-imap/src/main/resources/imapserver.xml
@@ -33,19 +33,8 @@ under the License.
         <connectionLimitPerIP>0</connectionLimitPerIP>
         <plainAuthDisallowed>false</plainAuthDisallowed>
         <gracefulShutdown>false</gracefulShutdown>
-    </imapserver>
-    <imapserver enabled="true">
-        <jmxName>imapserver-ssl</jmxName>
-        <bind>0.0.0.0:0</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <tls socketTLS="false" startTLS="true">
-            <keystore>classpath://keystore</keystore>
-            <secret>james72laBalle</secret>
-            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-        </tls>
-        <connectionLimit>0</connectionLimit>
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <gracefulShutdown>false</gracefulShutdown>
+        <customProperties>pong.response=customImapParameter</customProperties>
+        <customProperties>prop.b=anotherValue</customProperties>
     </imapserver>
     <imapPackages>org.apache.james.modules.protocols.DefaultImapPackage</imapPackages>
     <imapPackages>org.apache.james.examples.imap.PingImapPackages</imapPackages>
diff --git a/examples/custom-imap/src/test/java/org/apache/james/examples/imap/ImapCustomPackagesTest.java b/examples/custom-imap/src/test/java/org/apache/james/examples/imap/ImapCustomPackagesTest.java
index cc50e91782..b9ff7387c5 100644
--- a/examples/custom-imap/src/test/java/org/apache/james/examples/imap/ImapCustomPackagesTest.java
+++ b/examples/custom-imap/src/test/java/org/apache/james/examples/imap/ImapCustomPackagesTest.java
@@ -39,7 +39,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-public class ImapCustomPackagesTest {
+class ImapCustomPackagesTest {
 
     @RegisterExtension
     static JamesServerExtension jamesServerExtension = new JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
@@ -67,4 +67,11 @@ public class ImapCustomPackagesTest {
             .contains("PONG");
     }
 
+    @Test
+    void imapServerShouldSupportCustomConfigurationValues(GuiceJamesServer server) throws IOException {
+        assertThat(new TestIMAPClient().connect("127.0.0.1", server.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(BOB, BOB_PASSWORD)
+            .sendCommand("PING"))
+            .contains("customImapParameter");
+    }
 }
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConfiguration.java b/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConfiguration.java
index bb92d5b6e3..f42a9117d8 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConfiguration.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConfiguration.java
@@ -21,6 +21,7 @@ package org.apache.james.imap.api;
 
 import java.time.Duration;
 import java.util.Optional;
+import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang3.StringUtils;
@@ -58,6 +59,7 @@ public class ImapConfiguration {
         private Optional<Boolean> enableIdle;
         private ImmutableSet<String> disabledCaps;
         private Optional<Boolean> isCondstoreEnable;
+        private Optional<Properties> customProperties;
 
         private Builder() {
             this.appendLimit = Optional.empty();
@@ -68,6 +70,7 @@ public class ImapConfiguration {
             this.enableIdle = Optional.empty();
             this.disabledCaps = ImmutableSet.of();
             this.isCondstoreEnable = Optional.empty();
+            this.customProperties = Optional.empty();
         }
 
         public Builder idleTimeInterval(long idleTimeInterval) {
@@ -127,6 +130,11 @@ public class ImapConfiguration {
             return this;
         }
 
+        public Builder withCustomProperties(Properties customProperties) {
+            this.customProperties = Optional.of(customProperties);
+            return this;
+        }
+
         public ImapConfiguration build() {
             ImmutableSet<Capability> normalizeDisableCaps = disabledCaps.stream()
                     .filter(Builder::noBlankString)
@@ -141,7 +149,8 @@ public class ImapConfiguration {
                     maxQueueSize.orElse(DEFAULT_QUEUE_SIZE),
                     idleTimeIntervalUnit.orElse(DEFAULT_HEARTBEAT_INTERVAL_UNIT),
                     normalizeDisableCaps,
-                    isCondstoreEnable.orElse(DEFAULT_CONDSTORE_DISABLE));
+                    isCondstoreEnable.orElse(DEFAULT_CONDSTORE_DISABLE),
+                    customProperties.orElseGet(Properties::new));
         }
     }
 
@@ -153,8 +162,9 @@ public class ImapConfiguration {
     private final ImmutableSet<Capability> disabledCaps;
     private final boolean enableIdle;
     private final boolean isCondstoreEnable;
+    private final Properties customProperties;
 
-    private ImapConfiguration(Optional<Long> appendLimit, boolean enableIdle, long idleTimeInterval, int concurrentRequests, int maxQueueSize, TimeUnit idleTimeIntervalUnit, ImmutableSet<Capability> disabledCaps, boolean isCondstoreEnable) {
+    private ImapConfiguration(Optional<Long> appendLimit, boolean enableIdle, long idleTimeInterval, int concurrentRequests, int maxQueueSize, TimeUnit idleTimeIntervalUnit, ImmutableSet<Capability> disabledCaps, boolean isCondstoreEnable, Properties customProperties) {
         this.appendLimit = appendLimit;
         this.enableIdle = enableIdle;
         this.idleTimeInterval = idleTimeInterval;
@@ -163,6 +173,7 @@ public class ImapConfiguration {
         this.idleTimeIntervalUnit = idleTimeIntervalUnit;
         this.disabledCaps = disabledCaps;
         this.isCondstoreEnable = isCondstoreEnable;
+        this.customProperties = customProperties;
     }
 
     public Optional<Long> getAppendLimit() {
@@ -201,6 +212,10 @@ public class ImapConfiguration {
         return Duration.of(getIdleTimeInterval(), getIdleTimeIntervalUnit().toChronoUnit());
     }
 
+    public Properties getCustomProperties() {
+        return customProperties;
+    }
+
     @Override
     public final boolean equals(Object obj) {
         if (obj instanceof ImapConfiguration) {
@@ -212,6 +227,7 @@ public class ImapConfiguration {
                 && Objects.equal(that.getConcurrentRequests(), concurrentRequests)
                 && Objects.equal(that.getMaxQueueSize(), maxQueueSize)
                 && Objects.equal(that.getDisabledCaps(), disabledCaps)
+                && Objects.equal(that.getCustomProperties(), customProperties)
                 && Objects.equal(that.isCondstoreEnable(), isCondstoreEnable);
         }
         return false;
@@ -220,7 +236,7 @@ public class ImapConfiguration {
     @Override
     public final int hashCode() {
         return Objects.hashCode(enableIdle, idleTimeInterval, idleTimeIntervalUnit, disabledCaps, isCondstoreEnable,
-            concurrentRequests, maxQueueSize, appendLimit);
+            concurrentRequests, maxQueueSize, appendLimit, customProperties);
     }
 
     @Override
@@ -234,6 +250,7 @@ public class ImapConfiguration {
                 .add("isCondstoreEnable", isCondstoreEnable)
                 .add("concurrentRequests", concurrentRequests)
                 .add("maxQueueSize", maxQueueSize)
+                .add("customProperties", customProperties)
                 .toString();
     }
 }
diff --git a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
index 073db65280..0ce7dd543e 100644
--- a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
+++ b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
@@ -202,6 +202,7 @@ public class IMAPServer extends AbstractConfigurableAsyncServer implements ImapC
                 .appendLimit(Optional.of(parseLiteralSizeLimit(configuration)).filter(i -> i > 0))
                 .maxQueueSize(configuration.getInteger("maxQueueSize", ImapConfiguration.DEFAULT_QUEUE_SIZE))
                 .concurrentRequests(configuration.getInteger("concurrentRequests", ImapConfiguration.DEFAULT_CONCURRENT_REQUESTS))
+                .withCustomProperties(configuration.getProperties("customProperties"))
                 .build();
     }
 
diff --git a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerConfigurationTest.java b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerConfigurationTest.java
index d8060a3fda..4a73081d1d 100644
--- a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerConfigurationTest.java
+++ b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerConfigurationTest.java
@@ -21,6 +21,7 @@ package org.apache.james.imapserver.netty;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
@@ -57,8 +58,13 @@ class IMAPServerConfigurationTest {
         configurationBuilder.addProperty("concurrentRequests", "42");
         configurationBuilder.addProperty("idleTimeIntervalUnit", "MINUTES");
         configurationBuilder.addProperty("disabledCaps", "ACL | MOVE");
+        configurationBuilder.addProperty("customProperties", "abc=def");
+        configurationBuilder.addProperty("customProperties", "ghi=jkl");
         ImapConfiguration imapConfiguration = IMAPServer.getImapConfiguration(configurationBuilder);
 
+        Properties customProperties = new Properties();
+        customProperties.put("abc", "def");
+        customProperties.put("ghi", "jkl");
         ImapConfiguration expectImapConfiguration = ImapConfiguration.builder()
                 .enableIdle(false)
                 .idleTimeInterval(1)
@@ -66,6 +72,7 @@ class IMAPServerConfigurationTest {
                 .disabledCaps(ImmutableSet.of("ACL", "MOVE"))
                 .maxQueueSize(12)
                 .concurrentRequests(42)
+                .withCustomProperties(customProperties)
                 .build();
 
         assertThat(imapConfiguration).isEqualTo(expectImapConfiguration);


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