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]
