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 9dcc5422e2173f6114f15e4c8cd8dd163c10d678
Author: ouvtam <[email protected]>
AuthorDate: Tue Apr 7 08:31:44 2026 +0200

    JAMES-4199 ensure MailQueueIterator is closed to prevent memory leaks (e.g. 
ActiveMQ leaking open browsers)
---
 .../james/webadmin/routes/MailQueueRoutes.java     |  5 +-
 .../james/queue/api/ManageableMailQueue.java       |  3 +-
 .../james/queue/library/MailQueueManagement.java   | 90 +++++++++++-----------
 3 files changed, 50 insertions(+), 48 deletions(-)

diff --git 
a/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
 
b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
index 037b16320e..9605d9ba29 100644
--- 
a/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
@@ -36,6 +36,7 @@ import 
org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.MailQueueName;
 import org.apache.james.queue.api.ManageableMailQueue;
+import org.apache.james.queue.api.ManageableMailQueue.MailQueueIterator;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskManager;
 import org.apache.james.util.streams.Iterators;
@@ -185,8 +186,8 @@ public class MailQueueRoutes implements Routes {
     }
 
     private List<MailQueueItemDTO> listMails(ManageableMailQueue queue, 
Optional<Boolean> isDelayed, Limit limit) {
-        try (MailQueue closeable = queue) {
-            return limit.applyOnStream(Iterators.toStream(queue.browse()))
+        try (MailQueue closeable = queue; MailQueueIterator iter = 
queue.browse()) {
+            return limit.applyOnStream(Iterators.toStream(iter))
                     
.map(Throwing.function(MailQueueItemDTO::from).sneakyThrow())
                     .filter(item -> filter(item, isDelayed))
                     .collect(ImmutableList.toImmutableList());
diff --git 
a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/ManageableMailQueue.java
 
b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/ManageableMailQueue.java
index 1142eca17b..ffc85db27d 100644
--- 
a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/ManageableMailQueue.java
+++ 
b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/ManageableMailQueue.java
@@ -106,12 +106,13 @@ public interface ManageableMailQueue extends MailQueue {
      * {@link Iterator} subclass which allows to browse the content of a queue.
      * The content is not meant to be modifiable, everything is just READ-ONLY!
      */
-    interface MailQueueIterator extends Iterator<MailQueueItemView> {
+    interface MailQueueIterator extends Iterator<MailQueueItemView>, 
AutoCloseable {
 
         /**
          * Close the iterator. After this was called the iterator MUST NOT be
          * used again
          */
+        @Override
         void close();
     }
 
diff --git 
a/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
 
b/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
index 54695add2d..1b39e7c215 100644
--- 
a/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
+++ 
b/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
@@ -114,55 +114,55 @@ public class MailQueueManagement extends StandardMBean 
implements MailQueueManag
 
     @Override
     public List<CompositeData> browse() throws Exception {
-        MailQueueIterator it = queue.browse();
-        List<CompositeData> data = new ArrayList<>();
-        String[] names = new String[]{"name", "sender", "state", "recipients", 
"size", "lastUpdated", "remoteAddress", "remoteHost", "errorMessage", 
"attributes", "nextDelivery"};
-        String[] descs = new String[]{"Unique name", "Sender", "Current 
state", "Recipients", "Size in bytes", "Timestamp of last update", "IPAddress 
of the sender", "Hostname of the sender", "Errormessage if any", "Attributes 
stored", "Timestamp of when the next delivery attempt will be make"};
-        OpenType<?>[] types = new OpenType<?>[]{SimpleType.STRING, 
SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.LONG, 
SimpleType.LONG, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, 
SimpleType.STRING, SimpleType.LONG};
-
-        while (it.hasNext()) {
-
-            MailQueueItemView mView = it.next();
-            Mail m = mView.getMail();
-            long nextDelivery = mView.getNextDelivery()
-                .map(time -> time.toInstant().toEpochMilli())
-                .orElse(-1L);
-            Map<String, Object> map = new HashMap<>();
-            map.put(names[0], m.getName());
-            String sender = m.getMaybeSender().asString(null);
-            map.put(names[1], sender);
-            map.put(names[2], m.getState());
-
-            StringBuilder rcptsBuilder = new StringBuilder();
-            Collection<MailAddress> rcpts = m.getRecipients();
-            if (rcpts != null) {
-                Iterator<MailAddress> rcptsIt = rcpts.iterator();
-                while (rcptsIt.hasNext()) {
-                    rcptsBuilder.append(rcptsIt.next().toString());
-                    if (rcptsIt.hasNext()) {
-                        rcptsBuilder.append(",");
+        try (MailQueueIterator it = queue.browse()) {
+            List<CompositeData> data = new ArrayList<>();
+            String[] names = new String[] {"name", "sender", "state", 
"recipients", "size", "lastUpdated", "remoteAddress", "remoteHost", 
"errorMessage", "attributes", "nextDelivery"};
+            String[] descs = new String[] {"Unique name", "Sender", "Current 
state", "Recipients", "Size in bytes", "Timestamp of last update", "IPAddress 
of the sender", "Hostname of the sender", "Errormessage if any", "Attributes 
stored", "Timestamp of when the next delivery attempt will be make"};
+            OpenType<?>[] types = new OpenType<?>[] {SimpleType.STRING, 
SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.LONG, 
SimpleType.LONG, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, 
SimpleType.STRING, SimpleType.LONG};
+
+            while (it.hasNext()) {
+
+                MailQueueItemView mView = it.next();
+                Mail m = mView.getMail();
+                long nextDelivery = mView.getNextDelivery()
+                    .map(time -> time.toInstant().toEpochMilli())
+                    .orElse(-1L);
+                Map<String, Object> map = new HashMap<>();
+                map.put(names[0], m.getName());
+                String sender = m.getMaybeSender().asString(null);
+                map.put(names[1], sender);
+                map.put(names[2], m.getState());
+
+                StringBuilder rcptsBuilder = new StringBuilder();
+                Collection<MailAddress> rcpts = m.getRecipients();
+                if (rcpts != null) {
+                    Iterator<MailAddress> rcptsIt = rcpts.iterator();
+                    while (rcptsIt.hasNext()) {
+                        rcptsBuilder.append(rcptsIt.next().toString());
+                        if (rcptsIt.hasNext()) {
+                            rcptsBuilder.append(",");
+                        }
                     }
                 }
+                map.put(names[3], rcptsBuilder.toString());
+                map.put(names[4], m.getMessageSize());
+                map.put(names[5], m.getLastUpdated().getTime());
+                map.put(names[6], m.getRemoteAddr());
+                map.put(names[7], m.getRemoteHost());
+                map.put(names[8], m.getErrorMessage());
+                Map<String, String> attrs = m.attributes()
+                    .collect(ImmutableMap.toImmutableMap(
+                        attribute -> attribute.getName().asString(),
+                        attribute -> attribute.getValue().value().toString()));
+
+                map.put(names[9], attrs.toString());
+                map.put(names[10], nextDelivery);
+                CompositeDataSupport c = new CompositeDataSupport(new 
CompositeType(Mail.class.getName(), "Queue Mail", names, descs, types), map);
+                data.add(c);
+                LifecycleUtil.dispose(mView);
             }
-            map.put(names[3], rcptsBuilder.toString());
-            map.put(names[4], m.getMessageSize());
-            map.put(names[5], m.getLastUpdated().getTime());
-            map.put(names[6], m.getRemoteAddr());
-            map.put(names[7], m.getRemoteHost());
-            map.put(names[8], m.getErrorMessage());
-            Map<String, String> attrs = m.attributes()
-                .collect(ImmutableMap.toImmutableMap(
-                    attribute -> attribute.getName().asString(),
-                    attribute -> attribute.getValue().value().toString()));
-
-            map.put(names[9], attrs.toString());
-            map.put(names[10], nextDelivery);
-            CompositeDataSupport c = new CompositeDataSupport(new 
CompositeType(Mail.class.getName(), "Queue Mail", names, descs, types), map);
-            data.add(c);
-            LifecycleUtil.dispose(mView);
+            return data;
         }
-        it.close();
-        return data;
     }
 
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to