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 0bd83e9f0e41342c9f2590b24163b67da44d1592
Author: Benoit TELLIER <btell...@linagora.com>
AuthorDate: Thu Nov 21 10:30:44 2024 +0100

    JAMES-4091 Allow describing opened IMAP channels
---
 .../apache/james/core/ConnectionDescription.java   | 35 +++++++---------
 .../james/core/ConnectionDescriptionSupplier.java  | 40 +++++++++---------
 .../james/imap/api/process/SelectedMailbox.java    |  2 +
 .../imap/processor/base/SelectedMailboxImpl.java   |  5 +++
 .../james/modules/protocols/IMAPServerModule.java  |  2 +
 .../james/modules/server/ServerRouteModule.java    |  5 +++
 .../apache/james/imapserver/netty/IMAPServer.java  | 45 +++++++++++++++++++-
 .../james/imapserver/netty/IMAPServerFactory.java  | 13 +++++-
 .../MemoryWebAdminServerIntegrationTest.java       | 37 +++++++++++++++++
 .../protocols/webadmin/webadmin-protocols/pom.xml  |  4 ++
 .../protocols/webadmin/ProtocolServerRoutes.java   | 48 +++++++++++++++++++++-
 11 files changed, 193 insertions(+), 43 deletions(-)

diff --git 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
 b/core/src/main/java/org/apache/james/core/ConnectionDescription.java
similarity index 55%
copy from 
server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
copy to core/src/main/java/org/apache/james/core/ConnectionDescription.java
index 5dbaa855c9..fc30273d82 100644
--- 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
+++ b/core/src/main/java/org/apache/james/core/ConnectionDescription.java
@@ -17,26 +17,19 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.webadmin.integration.memory;
+package org.apache.james.core;
 
-import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+import java.util.Map;
+import java.util.Optional;
 
-import org.apache.james.JamesServerBuilder;
-import org.apache.james.JamesServerExtension;
-import org.apache.james.MemoryJamesConfiguration;
-import org.apache.james.MemoryJamesServerMain;
-import org.apache.james.webadmin.integration.WebAdminServerIntegrationTest;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class MemoryWebAdminServerIntegrationTest extends 
WebAdminServerIntegrationTest {
-
-    @RegisterExtension
-    static JamesServerExtension jamesServerExtension = new 
JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
-        MemoryJamesConfiguration.builder()
-            .workingDirectory(tmpDir)
-            .configurationFromClasspath()
-            .usersRepository(DEFAULT)
-            .build())
-        .server(MemoryJamesServerMain::createServer)
-        .build();
-}
\ No newline at end of file
+public record ConnectionDescription(
+    String protocol,
+    String endpoint,
+    Optional<String> remoteAddress,
+    boolean isActive,
+    boolean isOpen,
+    boolean isWritable,
+    boolean isEncrypted,
+    Optional<Username> username,
+    Map<String, String> protocolSpecificInformation) {
+}
diff --git 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
 b/core/src/main/java/org/apache/james/core/ConnectionDescriptionSupplier.java
similarity index 56%
copy from 
server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
copy to 
core/src/main/java/org/apache/james/core/ConnectionDescriptionSupplier.java
index 5dbaa855c9..16fa7ba6ae 100644
--- 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
+++ 
b/core/src/main/java/org/apache/james/core/ConnectionDescriptionSupplier.java
@@ -17,26 +17,28 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.webadmin.integration.memory;
+package org.apache.james.core;
 
-import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+import java.util.Set;
+import java.util.stream.Stream;
 
-import org.apache.james.JamesServerBuilder;
-import org.apache.james.JamesServerExtension;
-import org.apache.james.MemoryJamesConfiguration;
-import org.apache.james.MemoryJamesServerMain;
-import org.apache.james.webadmin.integration.WebAdminServerIntegrationTest;
-import org.junit.jupiter.api.extension.RegisterExtension;
+import jakarta.inject.Inject;
 
-class MemoryWebAdminServerIntegrationTest extends 
WebAdminServerIntegrationTest {
+public interface ConnectionDescriptionSupplier {
+    class CompositeConnectionDescriptionSupplier implements 
ConnectionDescriptionSupplier {
+        private final Set<ConnectionDescriptionSupplier> 
connectionDescriptionSupplierSet;
 
-    @RegisterExtension
-    static JamesServerExtension jamesServerExtension = new 
JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
-        MemoryJamesConfiguration.builder()
-            .workingDirectory(tmpDir)
-            .configurationFromClasspath()
-            .usersRepository(DEFAULT)
-            .build())
-        .server(MemoryJamesServerMain::createServer)
-        .build();
-}
\ No newline at end of file
+        @Inject
+        public 
CompositeConnectionDescriptionSupplier(Set<ConnectionDescriptionSupplier> 
connectionDescriptionSupplierSet) {
+            this.connectionDescriptionSupplierSet = 
connectionDescriptionSupplierSet;
+        }
+
+        @Override
+        public Stream<ConnectionDescription> describeConnections() {
+            return connectionDescriptionSupplierSet.stream()
+                .flatMap(ConnectionDescriptionSupplier::describeConnections);
+        }
+    }
+
+    Stream<ConnectionDescription> describeConnections();
+}
diff --git 
a/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
 
b/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
index 5aed0be304..241c27c9c5 100644
--- 
a/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
+++ 
b/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
@@ -50,6 +50,8 @@ public interface SelectedMailbox {
 
     void unregisterIdle();
 
+    boolean isIdling();
+
     /**
      * Return the msg index of the given uid or {@link 
NullableMessageSequenceNumber#noMessage()} instance if no
      * message with the given uid was found
diff --git 
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
 
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
index 95af2d2ac2..6a94411c74 100644
--- 
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
+++ 
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
@@ -175,6 +175,11 @@ public class SelectedMailboxImpl implements 
SelectedMailbox, EventListener.React
         idleEventListener.set(null);
     }
 
+    @Override
+    public boolean isIdling() {
+        return idleEventListener.get() != null;
+    }
+
     @Override
     public Optional<MessageUid> getFirstUid() {
         return uidMsnConverter.getFirstUid();
diff --git 
a/server/container/guice/protocols/imap/src/main/java/org/apache/james/modules/protocols/IMAPServerModule.java
 
b/server/container/guice/protocols/imap/src/main/java/org/apache/james/modules/protocols/IMAPServerModule.java
index b79d43afa8..fcea6b9f6c 100644
--- 
a/server/container/guice/protocols/imap/src/main/java/org/apache/james/modules/protocols/IMAPServerModule.java
+++ 
b/server/container/guice/protocols/imap/src/main/java/org/apache/james/modules/protocols/IMAPServerModule.java
@@ -28,6 +28,7 @@ import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.ProtocolConfigurationSanitizer;
 import org.apache.james.RunArguments;
+import org.apache.james.core.ConnectionDescriptionSupplier;
 import org.apache.james.core.Disconnector;
 import org.apache.james.core.healthcheck.HealthCheck;
 import org.apache.james.filesystem.api.FileSystem;
@@ -119,6 +120,7 @@ public class IMAPServerModule extends AbstractModule {
         Multibinder.newSetBinder(binder(), 
HealthCheck.class).addBinding().to(IMAPHealthCheck.class);
 
         Multibinder.newSetBinder(binder(), 
Disconnector.class).addBinding().to(IMAPServerFactory.class);
+        Multibinder.newSetBinder(binder(), 
ConnectionDescriptionSupplier.class).addBinding().to(IMAPServerFactory.class);
     }
 
     @Provides
diff --git 
a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/ServerRouteModule.java
 
b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/ServerRouteModule.java
index f3e3af0556..8ebf41e2e0 100644
--- 
a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/ServerRouteModule.java
+++ 
b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/ServerRouteModule.java
@@ -20,6 +20,7 @@
 package org.apache.james.modules.server;
 
 import org.apache.james.DisconnectorNotifier;
+import org.apache.james.core.ConnectionDescriptionSupplier;
 import org.apache.james.core.Disconnector;
 import org.apache.james.protocols.lib.netty.AbstractServerFactory;
 import org.apache.james.protocols.webadmin.ProtocolServerRoutes;
@@ -39,10 +40,14 @@ public class ServerRouteModule extends AbstractModule {
             .to(ProtocolServerRoutes.class);
 
         Multibinder.newSetBinder(binder(), Disconnector.class);
+        Multibinder.newSetBinder(binder(), 
ConnectionDescriptionSupplier.class);
 
         bind(Disconnector.class).to(Disconnector.CompositeDisconnector.class);
         bind(Disconnector.CompositeDisconnector.class).in(Scopes.SINGLETON);
 
+        
bind(ConnectionDescriptionSupplier.class).to(ConnectionDescriptionSupplier.CompositeConnectionDescriptionSupplier.class);
+        
bind(ConnectionDescriptionSupplier.CompositeConnectionDescriptionSupplier.class).in(Scopes.SINGLETON);
+
         
bind(DisconnectorNotifier.class).to(DisconnectorNotifier.InVMDisconnectorNotifier.class);
         
bind(DisconnectorNotifier.InVMDisconnectorNotifier.class).in(Scopes.SINGLETON);
     }
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 f2e08114a6..a9bac1194a 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
@@ -18,7 +18,9 @@
  ****************************************************************/
 package org.apache.james.imapserver.netty;
 
+import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
+import java.net.SocketAddress;
 import java.net.URISyntaxException;
 import java.time.Duration;
 import java.util.LinkedHashMap;
@@ -26,18 +28,24 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
+import org.apache.james.core.ConnectionDescription;
+import org.apache.james.core.ConnectionDescriptionSupplier;
 import org.apache.james.core.Disconnector;
 import org.apache.james.core.Username;
 import org.apache.james.imap.api.ConnectionCheck;
 import org.apache.james.imap.api.ImapConfiguration;
 import org.apache.james.imap.api.ImapConstants;
 import org.apache.james.imap.api.process.ImapProcessor;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.api.process.SelectedMailbox;
 import org.apache.james.imap.decode.ImapDecoder;
 import org.apache.james.imap.encode.ImapEncoder;
+import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.metrics.api.GaugeRegistry;
 import org.apache.james.protocols.api.OidcSASLConfiguration;
 import org.apache.james.protocols.lib.netty.AbstractConfigurableAsyncServer;
@@ -59,6 +67,7 @@ import com.google.common.collect.ImmutableSet;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.group.DefaultChannelGroup;
@@ -70,7 +79,8 @@ import io.netty.util.concurrent.GlobalEventExecutor;
 /**
  * NIO IMAP Server which use Netty.
  */
-public class IMAPServer extends AbstractConfigurableAsyncServer implements 
ImapConstants, IMAPServerMBean, NettyConstants, Disconnector {
+public class IMAPServer extends AbstractConfigurableAsyncServer implements 
ImapConstants, IMAPServerMBean, NettyConstants,
+    Disconnector, ConnectionDescriptionSupplier {
     private static final Logger LOG = 
LoggerFactory.getLogger(IMAPServer.class);
 
     public static class AuthenticationConfiguration {
@@ -356,4 +366,37 @@ public class IMAPServer extends 
AbstractConfigurableAsyncServer implements ImapC
     ReactiveThrottler getReactiveThrottler() {
         return reactiveThrottler;
     }
+
+    @Override
+    public Stream<ConnectionDescription> describeConnections() {
+        return imapChannelGroup.stream()
+            .map(channel -> {
+                Optional<ImapSession> imapSession = 
Optional.ofNullable(channel.attr(IMAP_SESSION_ATTRIBUTE_KEY).get());
+                return new ConnectionDescription(
+                    "IMAP",
+                    jmxName,
+                    
Optional.ofNullable(channel.remoteAddress()).map(this::addressAsString),
+                    channel.isActive(),
+                    channel.isOpen(),
+                    channel.isWritable(),
+                    imapSession.map(ImapSession::isTLSActive).orElse(false),
+                    imapSession.flatMap(session -> 
Optional.ofNullable(session.getUserName())),
+                    ImmutableMap.of(
+                        "isCompressed", 
Boolean.toString(imapSession.map(ImapSession::isCompressionActive).orElse(false)),
+                        "selectedMailbox", imapSession.flatMap(session -> 
Optional.ofNullable(session.getSelected()))
+                            .map(SelectedMailbox::getMailboxId)
+                            .map(MailboxId::serialize)
+                            .orElse(""),
+                        "isIdling", 
Boolean.toString(imapSession.flatMap(session -> 
Optional.ofNullable(session.getSelected()))
+                            .map(SelectedMailbox::isIdling)
+                            .orElse(false))));
+            });
+    }
+
+    private String addressAsString(SocketAddress socketAddress) {
+        if (socketAddress instanceof InetSocketAddress address) {
+            return address.getAddress().getHostAddress();
+        }
+        return socketAddress.toString();
+    }
 }
diff --git 
a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServerFactory.java
 
b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServerFactory.java
index 9ddcdb30b0..ab89490095 100644
--- 
a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServerFactory.java
+++ 
b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServerFactory.java
@@ -21,11 +21,14 @@ package org.apache.james.imapserver.netty;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import jakarta.inject.Inject;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.tree.ImmutableNode;
+import org.apache.james.core.ConnectionDescription;
+import org.apache.james.core.ConnectionDescriptionSupplier;
 import org.apache.james.core.Disconnector;
 import org.apache.james.core.Username;
 import org.apache.james.filesystem.api.FileSystem;
@@ -41,7 +44,7 @@ import 
org.apache.james.protocols.lib.netty.AbstractServerFactory;
 
 import com.github.fge.lambdas.functions.ThrowingFunction;
 
-public class IMAPServerFactory extends AbstractServerFactory implements 
Disconnector {
+public class IMAPServerFactory extends AbstractServerFactory implements 
Disconnector, ConnectionDescriptionSupplier {
 
     protected final FileSystem fileSystem;
     protected final ThrowingFunction<HierarchicalConfiguration<ImmutableNode>, 
ImapSuite> imapSuiteProvider;
@@ -105,4 +108,12 @@ public class IMAPServerFactory extends 
AbstractServerFactory implements Disconne
             .map(server -> (IMAPServer) server)
             .forEach(imapServer -> imapServer.disconnect(username));
     }
+
+    @Override
+    public Stream<ConnectionDescription> describeConnections() {
+        return getServers()
+            .stream()
+            .map(server -> (IMAPServer) server)
+            .flatMap(IMAPServer::describeConnections);
+    }
 }
diff --git 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
index 5dbaa855c9..3c7821de06 100644
--- 
a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryWebAdminServerIntegrationTest.java
@@ -19,16 +19,28 @@
 
 package org.apache.james.webadmin.integration.memory;
 
+import static io.restassured.RestAssured.when;
 import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP;
+import static org.hamcrest.Matchers.is;
 
+import org.apache.james.GuiceJamesServer;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
 import org.apache.james.MemoryJamesConfiguration;
 import org.apache.james.MemoryJamesServerMain;
+import org.apache.james.modules.protocols.ImapGuiceProbe;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.TestIMAPClient;
 import org.apache.james.webadmin.integration.WebAdminServerIntegrationTest;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 class MemoryWebAdminServerIntegrationTest extends 
WebAdminServerIntegrationTest {
+    private static final String DOMAIN = "domain";
+    private static final String USERNAME = "bob@" + DOMAIN;
+    private static final String PASSWORD = "password";
 
     @RegisterExtension
     static JamesServerExtension jamesServerExtension = new 
JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
@@ -39,4 +51,29 @@ class MemoryWebAdminServerIntegrationTest extends 
WebAdminServerIntegrationTest
             .build())
         .server(MemoryJamesServerMain::createServer)
         .build();
+
+    @RegisterExtension
+    TestIMAPClient testIMAPClient = new TestIMAPClient();
+
+    @Test
+    void shouldDescribeConnectedImapChannels(GuiceJamesServer server) throws 
Exception {
+        int imapPort = server.getProbe(ImapGuiceProbe.class).getImapPort();
+
+        server.getProbe(DataProbeImpl.class).addUser(USERNAME, PASSWORD);
+
+        testIMAPClient.connect(LOCALHOST_IP, imapPort)
+            .login(USERNAME, PASSWORD)
+            .select("INBOX");
+
+        when()
+            .get("/servers/channels/" + USERNAME)
+            .prettyPeek()
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("[0].protocol", is("IMAP"))
+            .body("[0].endpoint", is("imapserver"))
+            .body("[0].username", is("bob@domain"))
+            .body("[0].isEncrypted", is(false))
+            .body("[0].isEncrypted", is(false));
+    }
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin/webadmin-protocols/pom.xml 
b/server/protocols/webadmin/webadmin-protocols/pom.xml
index 6c29a73f63..c166a8c465 100644
--- a/server/protocols/webadmin/webadmin-protocols/pom.xml
+++ b/server/protocols/webadmin/webadmin-protocols/pom.xml
@@ -58,6 +58,10 @@
             <artifactId>testing-base</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jdk8</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
diff --git 
a/server/protocols/webadmin/webadmin-protocols/src/main/java/org/apache/james/protocols/webadmin/ProtocolServerRoutes.java
 
b/server/protocols/webadmin/webadmin-protocols/src/main/java/org/apache/james/protocols/webadmin/ProtocolServerRoutes.java
index c1901f7f15..d1ba81ee72 100644
--- 
a/server/protocols/webadmin/webadmin-protocols/src/main/java/org/apache/james/protocols/webadmin/ProtocolServerRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-protocols/src/main/java/org/apache/james/protocols/webadmin/ProtocolServerRoutes.java
@@ -20,12 +20,16 @@
 package org.apache.james.protocols.webadmin;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import jakarta.inject.Inject;
 
 import org.apache.james.DisconnectorNotifier;
+import org.apache.james.core.ConnectionDescription;
+import org.apache.james.core.ConnectionDescriptionSupplier;
 import org.apache.james.core.Username;
 import org.apache.james.protocols.lib.netty.CertificateReloadable;
 import org.apache.james.util.Port;
@@ -46,19 +50,49 @@ import spark.Request;
 import spark.Service;
 
 public class ProtocolServerRoutes implements Routes {
+    record ConnectionDescriptionDTO(
+        String protocol,
+        String endpoint,
+        Optional<String> remoteAddress,
+        boolean isActive,
+        boolean isOpen,
+        boolean isWritable,
+        boolean isEncrypted,
+        Optional<String> username,
+        Map<String, String> protocolSpecificInformation) {
+
+        static ConnectionDescriptionDTO from(ConnectionDescription 
domainObject) {
+            return new ConnectionDescriptionDTO(domainObject.protocol(),
+                domainObject.endpoint(),
+                domainObject.remoteAddress(),
+                domainObject.isActive(),
+                domainObject.isOpen(),
+                domainObject.isWritable(),
+                domainObject.isEncrypted(),
+                domainObject.username().map(Username::asString),
+                domainObject.protocolSpecificInformation());
+        }
+    }
+
     public static final String SERVERS = "servers";
     public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
     public static final TypeReference<List<String>> LIST_OF_STRING = new 
TypeReference<>() {
 
     };
 
+    static {
+        OBJECT_MAPPER.registerModule(new Jdk8Module());
+    }
+
     private final Set<CertificateReloadable.Factory> servers;
     private final DisconnectorNotifier disconnector;
+    private final ConnectionDescriptionSupplier connectionDescriptionSupplier;
 
     @Inject
-    public ProtocolServerRoutes(Set<CertificateReloadable.Factory> servers, 
DisconnectorNotifier disconnector) {
+    public ProtocolServerRoutes(Set<CertificateReloadable.Factory> servers, 
DisconnectorNotifier disconnector, ConnectionDescriptionSupplier 
connectionDescriptionSupplier) {
         this.servers = servers;
         this.disconnector = disconnector;
+        this.connectionDescriptionSupplier = connectionDescriptionSupplier;
     }
 
     @Override
@@ -110,6 +144,18 @@ public class ProtocolServerRoutes implements Routes {
 
             return Responses.returnNoContent(response);
         });
+
+        service.get(SERVERS + "/channels", (request, response) -> 
OBJECT_MAPPER.writeValueAsString(connectionDescriptionSupplier.describeConnections()
+            .map(ConnectionDescriptionDTO::from)
+            .toList()));
+
+        service.get(SERVERS + "/channels/:user", (request, response) -> {
+            Username username = Username.of(request.params("user"));
+            return 
OBJECT_MAPPER.writeValueAsString(connectionDescriptionSupplier.describeConnections()
+                .filter(connectionDescription -> 
connectionDescription.username().map(username::equals).orElse(false))
+                .map(ConnectionDescriptionDTO::from)
+                .toList());
+        });
     }
 
     private Predicate<CertificateReloadable> filters(Request request) {


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

Reply via email to