From 0885d16ac22a0ecd2267bf3c8818a3a8a5a9dadb Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 31 Jul 2026 07:48:54 +0000
Subject: [PATCH] Fix CodeQL warning-severity alerts: missed wakeups, resource leaks, escaping threads (#790)

---
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextDebugLogPublisher.java                         |    6 
 opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateGlobalAcisTableMojo.java           |   39 ++-
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ChangeNumberIndexer.java |    7 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/AsynchronousTextWriter.java                        |   20 +
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java             |   15 +
 opendj-server-legacy/src/main/java/org/opends/server/types/LDIFImportConfig.java                                |   24 +
 opendj-server-legacy/src/main/java/org/opends/server/core/SearchOperationBasis.java                             |    2 
 opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java                 |    6 
 opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java                                 |   26 ++
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java                    |    6 
 opendj-server-legacy/src/main/java/org/opends/server/backends/task/TaskThread.java                              |    3 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/MultifileTextWriter.java                           |   16 +
 opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java                 |    2 
 opendj-server-legacy/src/main/java/org/opends/quicksetup/BuildInformation.java                                  |    6 
 opendj-server-legacy/src/main/java/org/opends/server/types/RecordingInputStream.java                            |    5 
 opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Base64.java                                   |   11 
 opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java                             |   14 
 opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ModifyAsync.java                           |   17 +
 opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java                         |    4 
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java                  |   19 +
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServerDomain.java            |   15 +
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java                           |   30 +-
 opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeSearcherQueue.java              |   22 +
 opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ZipExtractor.java                                 |    9 
 opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java              |    3 
 opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java                  |    4 
 opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java                    |    5 
 opendj-core/src/main/java/org/forgerock/opendj/security/OpenDJProvider.java                                     |    4 
 opendj-server-legacy/src/main/java/org/opends/server/plugins/profiler/ProfileViewer.java                        |   14 
 opendj-config/src/main/java/org/forgerock/opendj/config/client/MissingMandatoryPropertiesException.java         |    3 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java     |    4 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java                         |    6 
 opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JebTestCase.java                              |    3 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroup.java                               |    7 
 opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java                                |    6 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java                  |    4 
 opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/MakeLDIFInputStream.java                    |   26 ++
 opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java                         |   68 +++--
 opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java                           |    5 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAuditLogPublisher.java                         |    6 
 opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/FilterTextField.java          |    5 
 opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeUtils.java                            |   22 +
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/MessageHandler.java                     |    3 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java                        |    6 
 opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java                  |    3 
 opendj-server-legacy/src/main/java/org/opends/quicksetup/util/Utils.java                                        |   52 ++--
 opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/BrowserController.java              |    2 
 opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/CustomTree.java               |    5 
 opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroupMemberList.java                     |   19 +
 opendj-server-legacy/src/main/java/org/opends/server/tasks/InitializeTask.java                                  |   19 +
 50 files changed, 436 insertions(+), 192 deletions(-)

diff --git a/opendj-config/src/main/java/org/forgerock/opendj/config/client/MissingMandatoryPropertiesException.java b/opendj-config/src/main/java/org/forgerock/opendj/config/client/MissingMandatoryPropertiesException.java
index 926f445..64e0455 100644
--- a/opendj-config/src/main/java/org/forgerock/opendj/config/client/MissingMandatoryPropertiesException.java
+++ b/opendj-config/src/main/java/org/forgerock/opendj/config/client/MissingMandatoryPropertiesException.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.forgerock.opendj.config.client;
 
@@ -99,7 +100,7 @@
      * @return Returns the first exception that caused this exception.
      */
     @Override
-    public PropertyException getCause() {
+    public synchronized PropertyException getCause() {
         return causes.iterator().next();
     }
 
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/security/OpenDJProvider.java b/opendj-core/src/main/java/org/forgerock/opendj/security/OpenDJProvider.java
index b5cba5a..04f6c11 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/security/OpenDJProvider.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/security/OpenDJProvider.java
@@ -12,6 +12,7 @@
  * information: "Portions copyright [year] [name of copyright owner]".
  *
  * Copyright 2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.forgerock.opendj.security;
 
@@ -210,7 +211,8 @@
     }
 
     private static ConnectionFactory newLDIFConnectionFactory(final File ldifFile) throws IOException {
-        try (LDIFEntryReader reader = new LDIFEntryReader(new FileReader(ldifFile)).setSchema(SCHEMA)) {
+        try (FileReader ldifFileReader = new FileReader(ldifFile);
+                LDIFEntryReader reader = new LDIFEntryReader(ldifFileReader).setSchema(SCHEMA)) {
             final MemoryBackend backend = new MemoryBackend(SCHEMA, reader).enableVirtualAttributes(true);
             return newInternalConnectionFactory(new WriteLDIFOnUpdateRequestHandler(backend, ldifFile));
         }
diff --git a/opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateGlobalAcisTableMojo.java b/opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateGlobalAcisTableMojo.java
index 35e97ca..ac932de 100644
--- a/opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateGlobalAcisTableMojo.java
+++ b/opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateGlobalAcisTableMojo.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.forgerock.opendj.maven.doc;
 
@@ -102,12 +103,14 @@
      */
     private Map<String, String> getAciDescriptions() throws IOException {
         final Map<String, String> descriptions = new HashMap<>();
-        BufferedReader reader = new BufferedReader(new FileReader(configDotLdif));
-        String line;
-        while ((line = reader.readLine()) != null) {
-            if (line.startsWith("# @aci ")) {
-                String[] split = line.replace("# @aci ", "").split(":", 2);
-                descriptions.put(split[0], split[1]);
+        try (FileReader fileReader = new FileReader(configDotLdif);
+             BufferedReader reader = new BufferedReader(fileReader)) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if (line.startsWith("# @aci ")) {
+                    String[] split = line.replace("# @aci ", "").split(":", 2);
+                    descriptions.put(split[0], split[1]);
+                }
             }
         }
         return descriptions;
@@ -120,19 +123,21 @@
      * @throws IOException  Failed to read the LDIF.
      */
     private void readAcis(Map<String, String> descriptions) throws IOException {
-        LDIFEntryReader reader = new LDIFEntryReader(new FileInputStream(configDotLdif));
-        reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config"));
+        try (FileInputStream configStream = new FileInputStream(configDotLdif);
+             LDIFEntryReader reader = new LDIFEntryReader(configStream)) {
+            reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config"));
 
-        while (reader.hasNext()) {
-            Entry entry = reader.readEntry();
-            for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) {
-                Aci aci = new Aci();
-                aci.name = getName(attribute);
-                if (descriptions != null) {
-                    aci.description = descriptions.get(aci.name);
+            while (reader.hasNext()) {
+                Entry entry = reader.readEntry();
+                for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) {
+                    Aci aci = new Aci();
+                    aci.name = getName(attribute);
+                    if (descriptions != null) {
+                        aci.description = descriptions.get(aci.name);
+                    }
+                    aci.definition = AsciidocConverterUtils.escapeVerticalLine(attribute);
+                    allGlobalAcis.add(aci);
                 }
-                aci.definition = AsciidocConverterUtils.escapeVerticalLine(attribute);
-                allGlobalAcis.add(aci);
             }
         }
     }
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ModifyAsync.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ModifyAsync.java
index 6a14b5a..d3c7e8d 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ModifyAsync.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ModifyAsync.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.forgerock.opendj.examples;
@@ -78,20 +79,24 @@
         final String userName = args[2];
         final char[] password = args[3].toCharArray();
 
-        // Create the LDIF reader using either the named file, if provided, or stdin.
-        InputStream ldif;
+        // Read the LDIF from either the named file, if provided, or stdin. Only a file is closed
+        // here; stdin belongs to the caller.
+        final String[] ldifLines;
         if (args.length > 4) {
-            try {
-                ldif = new FileInputStream(args[4]);
+            try (InputStream ldif = new FileInputStream(args[4])) {
+                ldifLines = getInputLines(ldif);
             } catch (final FileNotFoundException e) {
                 System.err.println(e.getMessage());
                 System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
                 return;
+            } catch (final IOException e) {
+                System.err.println(e.getMessage());
+                System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue());
+                return;
             }
         } else {
-            ldif = System.in;
+            ldifLines = getInputLines(System.in);
         }
-        final String[] ldifLines = getInputLines(ldif);
 
         // Connect to the server, bind, and request the modifications.
         new LDAPConnectionFactory(hostName, port)
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
index 5288836..f48eda9 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2009-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.forgerock.opendj.examples;
@@ -80,8 +81,9 @@
 
         // Create the memory backend.
         final MemoryBackend backend;
-        try {
-            backend = new MemoryBackend(new LDIFEntryReader(new FileInputStream(ldifFileName)));
+        try (FileInputStream ldifStream = new FileInputStream(ldifFileName);
+                LDIFEntryReader ldifReader = new LDIFEntryReader(ldifStream)) {
+            backend = new MemoryBackend(ldifReader);
         } catch (final IOException e) {
             System.err.println(e.getMessage());
             System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Base64.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Base64.java
index 84d909d..ba022a8 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Base64.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Base64.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package com.forgerock.opendj.ldap.tools;
@@ -42,6 +43,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintStream;
+import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
@@ -246,11 +248,14 @@
             dataToDecode = encodedDataArg.getValue();
         } else {
             final boolean readFromFile = encodedDataFilePathArg.isPresent();
+            Reader source = null;
             BufferedReader reader = null;
             final String encodedDataFilePath = encodedDataFilePathArg.getValue();
             try {
-                reader = new BufferedReader(readFromFile ? new FileReader(encodedDataFilePath)
-                                                         : new InputStreamReader(System.in));
+                // Only a file is closed below; System.in belongs to the caller.
+                source = readFromFile ? new FileReader(encodedDataFilePath)
+                                      : new InputStreamReader(System.in);
+                reader = new BufferedReader(source);
                 final StringBuilder buffer = new StringBuilder();
                 String line;
                 while ((line = reader.readLine()) != null) {
@@ -270,7 +275,7 @@
                                        ERR_BASE64_CANNOT_READ_ENCODED_DATA.get(getExceptionMessage(e)));
             } finally {
                 if (readFromFile) {
-                    closeSilently(reader);
+                    closeSilently(reader, source);
                 }
             }
         }
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
index 1c22aa0..27581c4 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.forgerock.opendj.reactive;
 
@@ -701,7 +702,7 @@
                     // so notify here to allow the server startup to complete.
                     synchronized (waitListen) {
                         starting = false;
-                        waitListen.notify();
+                        waitListen.notifyAll();
                     }
                 }
 
@@ -719,7 +720,7 @@
                 // At this point, the connection Handler either started correctly or failed
                 // to start but the start process should be notified and resume its work in any cases.
                 synchronized (waitListen) {
-                    waitListen.notify();
+                    waitListen.notifyAll();
                 }
 
                 // If we have gotten here, then we are about to start listening
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/BrowserController.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/BrowserController.java
index 24f9dfe..acf1199 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/BrowserController.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/BrowserController.java
@@ -152,7 +152,7 @@
     connectionPool = cpool;
     connectionPool.addReferralAuthenticationListener(this);
 
-    refreshQueue = new NodeSearcherQueue("New red", 2);
+    refreshQueue = new NodeSearcherQueue("New red", 2).start();
 
     // NUMSUBORDINATE HACK
     // Create an empty hacker to avoid null value test.
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeSearcherQueue.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeSearcherQueue.java
index 5c4deaf..31d8793 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeSearcherQueue.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeSearcherQueue.java
@@ -39,6 +39,7 @@
   private final List<AbstractNodeTask> waitingQueue = new ArrayList<>();
   private final Map<BasicNode, AbstractNodeTask> workingList = new HashMap<>();
   private final ThreadGroup threadGroup;
+  private final List<Thread> threads = new ArrayList<>();
 
 
   /**
@@ -53,8 +54,23 @@
     for (int i = 0; i < threadCount; i++) {
       Thread t = new Thread(threadGroup, this, name + "[" + i + "]");
       t.setPriority(Thread.MIN_PRIORITY);
+      threads.add(t);
+    }
+  }
+
+  /**
+   * Starts the threads consuming this queue.
+   * <p>
+   * The threads are not started by the constructor so that {@code this} is not published to them
+   * before construction has completed.
+   *
+   * @return this queue
+   */
+  public NodeSearcherQueue start() {
+    for (Thread t : threads) {
       t.start();
     }
+    return this;
   }
 
   /**
@@ -83,7 +99,7 @@
       throw new IllegalArgumentException("null argument");
     }
     waitingQueue.add(nodeTask);
-    notify();
+    notifyAll();
 //    System.out.println("Queued " + nodeTask + " in " + _name);
   }
 
@@ -113,7 +129,7 @@
     if (task != null) {
       task.cancel();
     }
-    notify();
+    notifyAll();
   }
 
   /**
@@ -197,7 +213,7 @@
       throw new IllegalArgumentException("null argument");
     }
     workingList.remove(task.getNode());
-    notify();
+    notifyAll();
 //    System.out.println("Flushed " + task + " from " + _name);
   }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java
index 3e49e3e..99f8edc 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.opends.guitools.controlpanel.ui;
@@ -628,7 +629,7 @@
     }
     synchronized (entryReaderThread)
     {
-      entryReaderThread.notify();
+      entryReaderThread.notifyAll();
     }
   }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/CustomTree.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/CustomTree.java
index 535c42a..3010fac 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/CustomTree.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/CustomTree.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.guitools.controlpanel.ui.components;
 
@@ -278,7 +279,7 @@
   }
 
   @Override
-  public void addMouseListener(MouseListener mouseListener)
+  public synchronized void addMouseListener(MouseListener mouseListener)
   {
     super.addMouseListener(mouseListener);
     if (mouseListeners == null)
@@ -289,7 +290,7 @@
   }
 
   @Override
-  public void removeMouseListener(MouseListener mouseListener)
+  public synchronized void removeMouseListener(MouseListener mouseListener)
   {
     super.removeMouseListener(mouseListener);
     mouseListeners.remove(mouseListener);
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/FilterTextField.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/FilterTextField.java
index 6e18a3c..e7dfa39 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/FilterTextField.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/components/FilterTextField.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.opends.guitools.controlpanel.ui.components;
@@ -131,13 +132,13 @@
   }
 
   @Override
-  public void addActionListener(ActionListener listener)
+  public synchronized void addActionListener(ActionListener listener)
   {
     listeners.add(listener);
   }
 
   @Override
-  public void removeActionListener(ActionListener listener)
+  public synchronized void removeActionListener(ActionListener listener)
   {
     listeners.remove(listener);
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/BuildInformation.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/BuildInformation.java
index 4c2fdd4..55419fd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/BuildInformation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/BuildInformation.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.quicksetup;
 
@@ -61,6 +62,7 @@
     ProcessBuilder pb = new ProcessBuilder(args);
     InputStream is = null;
     OutputStream out = null;
+    BufferedReader reader = null;
     final boolean[] done = {false};
     try {
       Map<String, String> env = pb.environment();
@@ -100,7 +102,7 @@
         });
         t.start();
       }
-      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+      reader = new BufferedReader(new InputStreamReader(is));
       String line = reader.readLine();
       bi.values.put(NAME, line);
       StringBuilder sb = new StringBuilder();
@@ -154,7 +156,7 @@
 
     } finally {
       done[0] = true;
-      StaticUtils.close(is, out);
+      StaticUtils.close(reader, is, out);
     }
 
     // Make sure we got values for important properties that are used
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
index d4615d4..7f6b80a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
@@ -162,7 +162,7 @@
           application.notifyListeners(LocalizableMessage.raw(line));
           application.notifyListeners(application.getLineBreak());
         }
-      };
+      }.start();
 
       final BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()));
       new OutputReader(out)
@@ -174,7 +174,7 @@
           application.notifyListeners(LocalizableMessage.raw(line));
           application.notifyListeners(application.getLineBreak());
         }
-      };
+      }.start();
 
       return process.waitFor();
     }
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java
index 1a36124..5e0c2e7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.opends.quicksetup.util;
@@ -33,18 +34,23 @@
    */
   public abstract void processLine(String line);
 
+  private final Thread thread;
+
   /**
    * The protected constructor.
+   * <p>
+   * The reader is consumed until end of stream and then closed by this reader's thread, which is
+   * only launched by {@link #start()}.
    *
    * @param reader  the BufferedReader of the stop process.
    */
   public OutputReader(final BufferedReader reader) {
-    Thread t = new Thread(new Runnable() {
+    thread = new Thread(new Runnable() {
       @Override
       public void run() {
-        try {
+        try (BufferedReader in = reader) {
           String line;
-          while (null != (line = reader.readLine())) {
+          while (null != (line = in.readLine())) {
             processLine(line);
           }
         } catch (Throwable t) {
@@ -52,6 +58,18 @@
         }
       }
     });
-    t.start();
+  }
+
+  /**
+   * Starts consuming the reader in a background thread.
+   * <p>
+   * The thread is not started by the constructor so that {@code this} does not escape before
+   * construction of the subclass has completed.
+   *
+   * @return this reader
+   */
+  public OutputReader start() {
+    thread.start();
+    return this;
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java
index 6c2189d..3a7d24f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java
@@ -561,8 +561,9 @@
       Thread t = new Thread(new Runnable() {
         @Override
         public void run() {
-          try {
-            String line = reader.readLine();
+          // The reader is owned by this thread, which closes it once the stream is drained.
+          try (BufferedReader in = reader) {
+            String line = in.readLine();
             while (line != null) {
               if (application != null) {
                 LocalizableMessageBuilder buf = new LocalizableMessageBuilder();
@@ -581,7 +582,7 @@
                 isFirstLine = false;
               }
               logger.info(LocalizableMessage.raw("server: " + line));
-              line = reader.readLine();
+              line = in.readLine();
             }
           } catch (Throwable t) {
             if (application != null) {
@@ -646,9 +647,10 @@
         @Override
         public void run()
         {
-          try
+          // The reader is owned by this thread, which closes it once the stream is drained.
+          try (BufferedReader in = reader)
           {
-            String line = reader.readLine();
+            String line = in.readLine();
             while (line != null)
             {
               if (application != null) {
@@ -676,7 +678,7 @@
                 isFinished = true;
                 startedIdFound = true;
               }
-              line = reader.readLine();
+              line = in.readLine();
             }
           } catch (Throwable t)
           {
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/Utils.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/Utils.java
index 4117b84..a9692c4 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/Utils.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/Utils.java
@@ -166,40 +166,42 @@
       final Process process = pb.start();
       logger.info(LocalizableMessage.raw("launching " + args + " with env: " + env));
       InputStream is = process.getInputStream();
-      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-      String line;
       boolean errorDetected = false;
-      while (null != (line = reader.readLine()))
+      try (BufferedReader reader = new BufferedReader(new InputStreamReader(is)))
       {
-        logger.info(LocalizableMessage.raw("The output: " + line));
-        if (line.contains("ERROR:  The detected Java version"))
+        String line;
+        while (null != (line = reader.readLine()))
         {
-          if (isWindows())
+          logger.info(LocalizableMessage.raw("The output: " + line));
+          if (line.contains("ERROR:  The detected Java version"))
           {
-            // If we are running windows, the process get blocked waiting for
-            // user input.  Just wait for a certain time to print the output
-            // in the logger and then kill the process.
-            Thread t = new Thread(new Runnable()
+            if (isWindows())
             {
-              @Override
-              public void run()
+              // If we are running windows, the process get blocked waiting for
+              // user input.  Just wait for a certain time to print the output
+              // in the logger and then kill the process.
+              Thread t = new Thread(new Runnable()
               {
-                try
+                @Override
+                public void run()
                 {
-                  Thread.sleep(3000);
-                  // To see if the process is over, call the exitValue method.
-                  // If it is not over, a IllegalThreadStateException.
-                  process.exitValue();
+                  try
+                  {
+                    Thread.sleep(3000);
+                    // To see if the process is over, call the exitValue method.
+                    // If it is not over, a IllegalThreadStateException.
+                    process.exitValue();
+                  }
+                  catch (Throwable t)
+                  {
+                    process.destroy();
+                  }
                 }
-                catch (Throwable t)
-                {
-                  process.destroy();
-                }
-              }
-            });
-            t.start();
+              });
+              t.start();
+            }
+            errorDetected = true;
           }
-          errorDetected = true;
         }
       }
       process.waitFor();
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ZipExtractor.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ZipExtractor.java
index fe3542d..883f3fb 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ZipExtractor.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ZipExtractor.java
@@ -100,15 +100,22 @@
                                       Application app)
     throws FileNotFoundException, IllegalArgumentException
   {
-    this(new FileInputStream(zipFile),
+    // The name is validated before the stream is opened, otherwise the stream would leak when the
+    // validation fails.
+    this(openZipFile(zipFile),
       minRatio,
       maxRatio,
       numberZipEntries,
       zipFile.getName(),
       app);
+  }
+
+  private static FileInputStream openZipFile(File zipFile) throws FileNotFoundException
+  {
     if (!zipFile.getName().endsWith(".zip")) {
       throw new IllegalArgumentException("File must have extension .zip");
     }
+    return new FileInputStream(zipFile);
   }
 
   /**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
index a4e6c70..73cb4d4 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.backends.pluggable;
 
@@ -268,21 +269,24 @@
         {
           is = new InflaterInputStream(is);
         }
-        byte[] data = new byte[encodedEntryLen];
-        int readBytes;
-        int position = 0;
-        int leftToRead = encodedEntryLen;
-        // CipherInputStream does not read more than block size...
-        do
+        try (InputStream entryStream = is)
         {
-          if ((readBytes = is.read(data, position, leftToRead)) == -1 )
+          byte[] data = new byte[encodedEntryLen];
+          int readBytes;
+          int position = 0;
+          int leftToRead = encodedEntryLen;
+          // CipherInputStream does not read more than block size...
+          do
           {
-            throw DecodeException.error(ERR_CANNOT_DECODE_ENTRY.get());
-          }
-          position += readBytes;
-          leftToRead -= readBytes;
-        } while (leftToRead > 0 && readBytes > 0);
-        return Entry.decode(ByteString.wrap(data).asReader(), compressedSchema);
+            if ((readBytes = entryStream.read(data, position, leftToRead)) == -1 )
+            {
+              throw DecodeException.error(ERR_CANNOT_DECODE_ENTRY.get());
+            }
+            position += readBytes;
+            leftToRead -= readBytes;
+          } while (leftToRead > 0 && readBytes > 0);
+          return Entry.decode(ByteString.wrap(data).asReader(), compressedSchema);
+        }
       }
       catch (CryptoManagerException cme)
       {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/task/TaskThread.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/task/TaskThread.java
index 6ef3dd6..6963785 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/task/TaskThread.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/task/TaskThread.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2013-2014 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.backends.task;
 
@@ -102,7 +103,7 @@
 
     synchronized (notifyLock)
     {
-      notifyLock.notify();
+      notifyLock.notifyAll();
     }
   }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java
index faaab66..892643d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java
@@ -12,7 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2014-2016 ForgeRock AS.
- * Portions Copyright 2025 3A Systems,LLC
+ * Portions Copyright 2025-2026 3A Systems, LLC.
  */
 package org.opends.server.config;
 
@@ -1405,7 +1405,8 @@
   {
     byte[] buffer = new byte[8192];
     try(FileInputStream inputStream = new FileInputStream(configFile);
-        GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(archiveFile)))
+        FileOutputStream archiveStream = new FileOutputStream(archiveFile);
+        GZIPOutputStream outputStream = new GZIPOutputStream(archiveStream))
     {
       int bytesRead = inputStream.read(buffer);
       while (bytesRead > 0)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/SearchOperationBasis.java b/opendj-server-legacy/src/main/java/org/opends/server/core/SearchOperationBasis.java
index 9b3bb83..bde5544 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/SearchOperationBasis.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/SearchOperationBasis.java
@@ -911,7 +911,7 @@
   }
 
   @Override
-  public void abort(CancelRequest cancelRequest)
+  public synchronized void abort(CancelRequest cancelRequest)
   {
     if(cancelResult == null && this.cancelRequest == null)
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroup.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroup.java
index 20c2338..c171b9b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroup.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroup.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008-2010 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.extensions;
 
@@ -257,7 +258,7 @@
   public MemberList getMembers()
          throws DirectoryException
   {
-    return new DynamicGroupMemberList(groupEntryDN, memberURLs);
+    return new DynamicGroupMemberList(groupEntryDN, memberURLs).start();
   }
 
   @Override
@@ -267,12 +268,12 @@
   {
     if (baseDN == null && filter == null)
     {
-      return new DynamicGroupMemberList(groupEntryDN, memberURLs);
+      return new DynamicGroupMemberList(groupEntryDN, memberURLs).start();
     }
     else
     {
       return new DynamicGroupMemberList(groupEntryDN, memberURLs, baseDN, scope,
-                                        filter);
+                                        filter).start();
     }
   }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroupMemberList.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroupMemberList.java
index 99d622b..d3a785f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroupMemberList.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/DynamicGroupMemberList.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.extensions;
 
@@ -60,6 +61,9 @@
    */
   private final LinkedBlockingQueue<Object> resultQueue;
 
+  /** The background thread which performs the internal searches. */
+  private final DynamicGroupSearchThread searchThread;
+
   /** The search filter to use when filtering the set of group members. */
   private final SearchFilter filter;
 
@@ -292,9 +296,22 @@
       }
     }
 
-    DynamicGroupSearchThread searchThread =
+    searchThread =
          new DynamicGroupSearchThread(this, baseDNArray, filterArray, urlArray);
+  }
+
+  /**
+   * Starts the background searches which populate this member list.
+   * <p>
+   * The searches are not started by the constructor so that {@code this} is not published to the
+   * search thread before construction has completed.
+   *
+   * @return this member list
+   */
+  DynamicGroupMemberList start()
+  {
     searchThread.start();
+    return this;
   }
 
   /**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AsynchronousTextWriter.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AsynchronousTextWriter.java
index fe62576..b64a06e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AsynchronousTextWriter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AsynchronousTextWriter.java
@@ -43,7 +43,7 @@
 
   private String name;
   private AtomicBoolean stopRequested;
-  private WriterThread writerThread;
+  private final WriterThread writerThread;
 
   private boolean autoFlush;
 
@@ -65,16 +65,28 @@
 
     this.queue = new LinkedBlockingQueue<>(capacity);
     this.capacity = capacity;
-    this.writerThread = null;
     this.stopRequested = new AtomicBoolean(false);
 
     writerThread = new WriterThread();
-    writerThread.start();
 
     DirectoryServer.registerShutdownListener(this);
   }
 
   /**
+   * Starts the background thread which publishes the queued log records.
+   * <p>
+   * The thread is not started by the constructor so that {@code this} is not published to it before
+   * construction has completed.
+   *
+   * @return this writer
+   */
+  AsynchronousTextWriter start()
+  {
+    writerThread.start();
+    return this;
+  }
+
+  /**
    * The publisher thread is responsible for emptying the queue of log records
    * waiting to published.
    */
@@ -216,7 +228,7 @@
     stopRequested.set(true);
 
     // Wait for publisher thread to terminate
-    while (writerThread != null && writerThread.isAlive()) {
+    while (writerThread.isAlive()) {
       try {
         // Interrupt the thread if its blocking
         writerThread.interrupt();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/MultifileTextWriter.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/MultifileTextWriter.java
index 7fb0743..30372b1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/MultifileTextWriter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/MultifileTextWriter.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -134,12 +135,25 @@
     this.stopRequested = false;
 
     rotaterThread = new RotaterThread(this);
-    rotaterThread.start();
 
     DirectoryServer.registerShutdownListener(this);
   }
 
   /**
+   * Starts the background thread which rotates and retains the log files.
+   * <p>
+   * The thread is not started by the constructor so that {@code this} is not published to it before
+   * construction has completed.
+   *
+   * @return this writer
+   */
+  MultifileTextWriter start()
+  {
+    rotaterThread.start();
+    return this;
+  }
+
+  /**
    * Construct a PrintWriter for a file.
    * @param file - the file to open for writing
    * @param filePermissions - the file permissions to set on the file.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
index fe725ff..c7f2d04 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -242,6 +243,9 @@
         theWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
+      // Rotation only starts once the policies above are registered.
+      theWriter.start();
+
       if (cfg.isAsynchronous())
       {
         this.writer = newAsyncWriter(theWriter, cfg);
@@ -285,7 +289,7 @@
   private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedAccessLogPublisherCfg config)
   {
     String name = "Asynchronous Text Writer for " + config.dn();
-    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter);
+    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start();
   }
 
   @Override
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAuditLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAuditLogPublisher.java
index 4d4e72f..c856659 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAuditLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAuditLogPublisher.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -202,6 +203,9 @@
         writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
+      // Rotation only starts once the policies above are registered.
+      writer.start();
+
       if (cfg.isAsynchronous())
       {
         this.writer = newAsyncWriter(writer, cfg);
@@ -230,7 +234,7 @@
   private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter writer, FileBasedAuditLogPublisherCfg cfg)
   {
     String name = "Asynchronous Text Writer for " + cfg.dn();
-    return new AsynchronousTextWriter(name, cfg.getQueueSize(), cfg.isAutoFlush(), writer);
+    return new AsynchronousTextWriter(name, cfg.getQueueSize(), cfg.isAutoFlush(), writer).start();
   }
 
   @Override
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextDebugLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextDebugLogPublisher.java
index f42868f..1341774 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextDebugLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextDebugLogPublisher.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -133,6 +134,9 @@
         writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
+      // Rotation only starts once the policies above are registered.
+      writer.start();
+
       if(config.isAsynchronous())
       {
         this.writer = newAsyncWriter(writer, config);
@@ -271,7 +275,7 @@
   private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter writer, FileBasedDebugLogPublisherCfg config)
   {
     String name = "Asynchronous Text Writer for " + config.dn();
-    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), writer);
+    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), writer).start();
   }
 
   private void configure(MultifileTextWriter mfWriter, FileBasedDebugLogPublisherCfg config) throws DirectoryException
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
index 8f0de7a..a4cf446 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -126,6 +127,9 @@
         writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
+      // Rotation only starts once the policies above are registered.
+      writer.start();
+
       if(config.isAsynchronous())
       {
         this.writer = newAsyncWriter(writer, config);
@@ -396,7 +400,7 @@
   private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedErrorLogPublisherCfg config)
   {
     String name = "Asynchronous Text Writer for " + config.dn();
-    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter);
+    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start();
   }
 
   private void setDefaultSeverities(Set<ErrorLogPublisherCfgDefn.DefaultSeverity> defSevs)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
index 5b9607b..406269b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.loggers;
 
@@ -275,7 +276,7 @@
   private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedHTTPAccessLogPublisherCfg config)
   {
     String name = "Asynchronous Text Writer for " + config.dn();
-    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter);
+    return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start();
   }
 
   private LocalizableMessage setLogFormatFields(String logFormat)
@@ -336,6 +337,9 @@
         theWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
+      // Rotation only starts once the policies above are registered.
+      theWriter.start();
+
       if (cfg.isAsynchronous())
       {
         this.writer = newAsyncWriter(theWriter, cfg);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/plugins/profiler/ProfileViewer.java b/opendj-server-legacy/src/main/java/org/opends/server/plugins/profiler/ProfileViewer.java
index 30d8597..41c8575 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/plugins/profiler/ProfileViewer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/plugins/profiler/ProfileViewer.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.plugins.profiler;
 
@@ -214,11 +215,10 @@
    */
   public void processDataFile(String filename) throws IOException
   {
-    // Try to open the file for reading.
-    ASN1Reader reader = ASN1.getReader(new FileInputStream(filename));
-
-
-    try
+    // Both resources are declared here so that the file stream is closed as well if the reader
+    // cannot be created around it.
+    try (FileInputStream fileStream = new FileInputStream(filename);
+         ASN1Reader reader = ASN1.getReader(fileStream))
     {
       // The first element in the file must be a sequence with the header
       // information.
@@ -273,10 +273,6 @@
         existingFrame.recurseSubFrames(stack, pos-1, count, stacksByMethod);
       }
     }
-    finally
-    {
-      close(reader);
-    }
   }
 
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index e5219b0..af5b881 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.protocols.http;
 
@@ -165,6 +166,12 @@
    */
   private final Object waitListen = new Object();
 
+  /**
+   * The condition guarding {@link #waitListen}: set once the run method has tried to open the
+   * socket port, whether it succeeded or not. Guarded by {@link #waitListen}.
+   */
+  private boolean listenAttempted;
+
   /** The friendly name of this connection handler. */
   private String friendlyName;
 
@@ -579,11 +586,15 @@
 
       try
       {
-        waitListen.wait();
+        while (!listenAttempted)
+        {
+          waitListen.wait();
+        }
       }
       catch (InterruptedException e)
       {
         // If something interrupted the start its probably better to return ASAP
+        Thread.currentThread().interrupt();
       }
     }
   }
@@ -625,7 +636,8 @@
           synchronized (waitListen)
           {
             starting = false;
-            waitListen.notify();
+            listenAttempted = true;
+            waitListen.notifyAll();
           }
         }
 
@@ -646,7 +658,8 @@
         // to start but the start process should be notified and resume its work in any cases.
         synchronized (waitListen)
         {
-          waitListen.notify();
+          listenAttempted = true;
+          waitListen.notifyAll();
         }
 
         // If we have gotten here, then we are about to start listening
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 37a3256..f404bd9 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -873,7 +873,7 @@
           {
             starting = false;
             listenAttempted = true;
-            waitListen.notify();
+            waitListen.notifyAll();
           }
         }
 
@@ -897,7 +897,7 @@
         synchronized (waitListen)
         {
           listenAttempted = true;
-          waitListen.notify();
+          waitListen.notifyAll();
         }
 
         // If none of the listeners were created successfully, then
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 13c265a..2653da0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.replication.plugin;
 
@@ -2239,7 +2240,7 @@
         flushThread.initiateShutdown();
         synchronized (flushThread)
         {
-          flushThread.notify();
+          flushThread.notifyAll();
         }
       }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/MessageHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/MessageHandler.java
index d2cf741..9106352 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/MessageHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/MessageHandler.java
@@ -130,7 +130,7 @@
        */
       if (msgQueue.isEmpty())
       {
-        msgQueue.notify();
+        msgQueue.notifyAll();
       }
 
       msgQueue.add(update);
@@ -644,7 +644,6 @@
     synchronized (msgQueue)
     {
       msgQueue.clear();
-      msgQueue.notify();
       msgQueue.notifyAll();
     }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
index 29ba80d..b858f94 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
@@ -746,7 +746,7 @@
     {
       ReplicationServerDomain domain = baseDNs.get(baseDN);
       if (domain == null && create) {
-        domain = new ReplicationServerDomain(baseDN, this);
+        domain = new ReplicationServerDomain(baseDN, this).start();
         baseDNs.put(baseDN, domain);
       }
       return domain;
@@ -770,7 +770,7 @@
       }
 
       // Wake up connect thread.
-      connectThreadLock.notify();
+      connectThreadLock.notifyAll();
     }
 
     // Wait until the connect thread has processed next connect phase.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServerDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServerDomain.java
index 336124d..01dd007 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServerDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServerDomain.java
@@ -283,11 +283,24 @@
     this.domainDB =
         localReplicationServer.getChangelogDB().getReplicationDomainDB();
     this.statusAnalyzer = new StatusAnalyzer(this);
-    this.statusAnalyzer.start();
     DirectoryServer.registerMonitorProvider(this);
   }
 
   /**
+   * Starts the status analyzer of this domain.
+   * <p>
+   * The analyzer is not started by the constructor so that {@code this} is not published to its
+   * thread before construction has completed.
+   *
+   * @return this domain
+   */
+  ReplicationServerDomain start()
+  {
+    statusAnalyzer.start();
+    return this;
+  }
+
+  /**
    * Add an update that has been received to the list of
    * updates that must be forwarded to all other servers.
    *
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ChangeNumberIndexer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ChangeNumberIndexer.java
index c1ee673..8ac77cd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ChangeNumberIndexer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ChangeNumberIndexer.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.replication.server.changelog.file;
 
@@ -221,7 +222,7 @@
     {
       synchronized (this)
       {
-        notify();
+        notifyAll();
       }
     }
   }
@@ -364,7 +365,7 @@
     super.initiateShutdown();
     synchronized (this)
     {
-      notify();
+      notifyAll();
     }
   }
 
@@ -590,7 +591,7 @@
       // wait until clear() has been done by thread, always waking it up
       synchronized (this)
       {
-        notify();
+        notifyAll();
       }
       // ensures thread wait that this thread's state is cleaned up
       Thread.yield();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
index cc09070..2164ae9 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
@@ -593,7 +593,7 @@
       final ChangelogDBPurger currentPurger = cnPurger.get();
       synchronized (currentPurger)
       {
-        currentPurger.notify();
+        currentPurger.notifyAll();
       }
     }
   }
@@ -1017,7 +1017,7 @@
       super.initiateShutdown();
       synchronized (this)
       {
-        notify(); // wake up the purger thread for faster shutdown
+        notifyAll(); // wake up the purger thread for faster shutdown
       }
     }
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
index 31cbb71..77a35ef 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.replication.server.changelog.file;
 
@@ -112,8 +113,18 @@
     if (isWriteEnabled)
     {
       ensureLogFileIsValid(parser);
-      writer = BlockLogWriter.newWriter(new LogWriter(logfile), parser);
-      initializeNewestRecord();
+      final LogWriter logWriter = new LogWriter(logfile);
+      try
+      {
+        writer = BlockLogWriter.newWriter(logWriter, parser);
+        initializeNewestRecord();
+      }
+      catch (ChangelogException | RuntimeException e)
+      {
+        // The writer is not reachable from a half-constructed log file, so close it here.
+        StaticUtils.close(logWriter);
+        throw e;
+      }
     }
     else
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
index 3015639..9e59eb1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
@@ -829,7 +829,7 @@
       final ConnectedRS rs = connectedRS.get();
       if (rs.isConnected())
       {
-        connectPhaseLock.notify();
+        connectPhaseLock.notifyAll();
 
         final long rsGenId = rs.rsInfo.getGenerationId();
         final int rsServerId = rs.rsInfo.getServerId();
@@ -851,7 +851,7 @@
         if (!connectionError)
         {
           connectionError = true;
-          connectPhaseLock.notify();
+          connectPhaseLock.notifyAll();
 
           if (!rsInfos.isEmpty())
           {
@@ -2510,7 +2510,7 @@
           synchronized (monitorResponse)
           {
             monitorResponse.set(true);
-            monitorResponse.notify();
+            monitorResponse.notifyAll();
           }
 
           // Update the replication servers ServerStates with new received info
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
index 8cc140a..2d9f175 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
@@ -953,7 +953,7 @@
     {
       synchronized (update)
       {
-        update.notify();
+        update.notifyAll();
       }
 
       // Analyze status of embedded in the ack to see if everything went well
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tasks/InitializeTask.java b/opendj-server-legacy/src/main/java/org/opends/server/tasks/InitializeTask.java
index 921c2d4..d3c080d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tasks/InitializeTask.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tasks/InitializeTask.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
  * Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.tasks;
 
@@ -42,7 +43,15 @@
   private String domainString;
   private int  source;
   private LDAPReplicationDomain domain;
-  private TaskState initState;
+  /**
+   * The monitor used to signal the completion of the import to {@link #runTask()}.
+   * <p>
+   * A dedicated lock is required because {@link #initState} is reassigned: synchronizing on the
+   * state itself would lock the monitor of an enum constant which is both shared JVM wide and
+   * different for the waiting and the notifying thread.
+   */
+  private final Object initStateLock = new Object();
+  private volatile TaskState initState;
 
   /** The total number of entries expected to be processed when this import will end successfully. */
   private long total;
@@ -103,12 +112,12 @@
       // launch the import
       domain.initializeFromRemote(source, this);
 
-      synchronized(initState)
+      synchronized (initStateLock)
       {
         // Waiting for the end of the job
         while (initState == TaskState.RUNNING)
         {
-          initState.wait(1000);
+          initStateLock.wait(1000);
           replaceAttributeValue(ATTR_TASK_INITIALIZE_LEFT, String.valueOf(left));
           replaceAttributeValue(ATTR_TASK_INITIALIZE_DONE, String.valueOf(total-left));
         }
@@ -158,9 +167,9 @@
     finally
     {
       // Wake up runTask method waiting for completion
-      synchronized (initState)
+      synchronized (initStateLock)
       {
-        initState.notify();
+        initStateLock.notifyAll();
       }
     }
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java
index e59ccdf..c4fe83f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.tools;
 
@@ -270,25 +271,27 @@
     {
       String serviceName = null;
       Process p = Runtime.getRuntime().exec(cmd);
-      BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
-      boolean processDone = false;
-      String s;
-      while (!processDone)
+      try (BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream())))
       {
-        try
+        boolean processDone = false;
+        String s;
+        while (!processDone)
         {
-          p.exitValue();
-          processDone = true;
-        }
-        catch (Throwable t)
-        {
-        }
-        while ((s = stdout.readLine()) != null)
-        {
-          serviceName = s;
-          if (serviceName.trim().length() == 0)
+          try
           {
-            serviceName = null;
+            p.exitValue();
+            processDone = true;
+          }
+          catch (Throwable t)
+          {
+          }
+          while ((s = stdout.readLine()) != null)
+          {
+            serviceName = s;
+            if (serviceName.trim().length() == 0)
+            {
+              serviceName = null;
+            }
           }
         }
       }
@@ -608,25 +611,26 @@
     {
       int resultCode = -1;
       Process process = new ProcessBuilder(cmd).start();
-      BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
-
-      boolean processDone = false;
-      String s;
-      while (!processDone)
+      try (BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())))
       {
-        try
+        boolean processDone = false;
+        String s;
+        while (!processDone)
         {
-          resultCode = process.exitValue();
-          processDone = true;
-        }
-        catch (Throwable t)
-        {
-        }
-        while ((s = stdout.readLine()) != null)
-        {
-          if (s.trim().length() != 0)
+          try
           {
-            serviceName = s;
+            resultCode = process.exitValue();
+            processDone = true;
+          }
+          catch (Throwable t)
+          {
+          }
+          while ((s = stdout.readLine()) != null)
+          {
+            if (s.trim().length() != 0)
+            {
+              serviceName = s;
+            }
           }
         }
       }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/MakeLDIFInputStream.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/MakeLDIFInputStream.java
index 3df8112..c41fb87 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/MakeLDIFInputStream.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/MakeLDIFInputStream.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.tools.makeldif;
 
@@ -65,13 +66,16 @@
   /** The queue used to hold generated entries until they can be read. */
   private LinkedBlockingQueue<TemplateEntry> entryQueue;
 
+  /** The background thread used to actually generate the entries. */
+  private final MakeLDIFInputStreamThread generatorThread;
+
   /**
    * Creates a new MakeLDIF input stream that will generate entries based on the
    * provided template file.
    *
    * @param  templateFile  The template file to use to generate the entries.
    */
-  public MakeLDIFInputStream(TemplateFile templateFile)
+  private MakeLDIFInputStream(TemplateFile templateFile)
   {
     allGenerated = false;
     closed       = false;
@@ -93,7 +97,25 @@
     }
 
     /* The background thread being used to actually generate the entries. */
-    new MakeLDIFInputStreamThread(this, templateFile).start();
+    generatorThread = new MakeLDIFInputStreamThread(this, templateFile);
+  }
+
+  /**
+   * Creates a new MakeLDIF input stream based on the provided template file and starts generating
+   * entries in the background.
+   * <p>
+   * The generator thread is started here rather than by the constructor so that {@code this} is not
+   * published to it before construction has completed.
+   *
+   * @param  templateFile  The template file to use to generate the entries.
+   *
+   * @return  A new input stream which has started generating entries.
+   */
+  public static MakeLDIFInputStream newStartedInputStream(TemplateFile templateFile)
+  {
+    MakeLDIFInputStream inputStream = new MakeLDIFInputStream(templateFile);
+    inputStream.generatorThread.start();
+    return inputStream;
   }
 
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeUtils.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeUtils.java
index 8d96700..214f6b1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeUtils.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeUtils.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.tools.upgrade;
 
@@ -54,6 +55,7 @@
 import org.forgerock.opendj.ldif.LDIFEntryReader;
 import org.forgerock.opendj.ldif.LDIFEntryWriter;
 import org.forgerock.util.Reject;
+import org.forgerock.util.Utils;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.util.ChangeOperationType;
 import org.opends.server.util.SchemaUtils;
@@ -304,8 +306,18 @@
   {
     final Schema schema = getUpgradeSchema();
     final File configFile = new File(configDirectory, CURRENT_CONFIG_FILE_NAME);
-    final LDIFEntryReader entryReader = new LDIFEntryReader(new FileInputStream(configFile)).setSchema(schema);
-    return LDIF.search(entryReader, searchRequest, schema);
+    final FileInputStream configStream = new FileInputStream(configFile);
+    try
+    {
+      // Ownership of the stream passes to the returned reader, which the caller must close.
+      final LDIFEntryReader entryReader = new LDIFEntryReader(configStream).setSchema(schema);
+      return LDIF.search(entryReader, searchRequest, schema);
+    }
+    catch (RuntimeException e)
+    {
+      Utils.closeSilently(configStream);
+      throw e;
+    }
   }
 
   /**
@@ -333,8 +345,10 @@
 
     int changeCount = 0;
     final Schema schema = getUpgradeSchema();
-    try (LDIFEntryReader entryReader = new LDIFEntryReader(new FileInputStream(configFile)).setSchema(schema);
-        LDIFEntryWriter writer = new LDIFEntryWriter(new FileOutputStream(copyConfig)))
+    try (FileInputStream configStream = new FileInputStream(configFile);
+        LDIFEntryReader entryReader = new LDIFEntryReader(configStream).setSchema(schema);
+        FileOutputStream copyStream = new FileOutputStream(copyConfig);
+        LDIFEntryWriter writer = new LDIFEntryWriter(copyStream))
     {
       writer.setWrapColumn(80);
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/LDIFImportConfig.java b/opendj-server-legacy/src/main/java/org/opends/server/types/LDIFImportConfig.java
index 2dc13f3..c6a0c96 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/LDIFImportConfig.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/LDIFImportConfig.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.types;
 
@@ -203,7 +204,7 @@
    */
   public LDIFImportConfig(TemplateFile templateFile)
   {
-    this(new MakeLDIFInputStream(templateFile));
+    this(MakeLDIFInputStream.newStartedInputStream(templateFile));
   }
 
 
@@ -243,7 +244,7 @@
 
       if (isCompressed)
       {
-        inputStream = new GZIPInputStream(inputStream);
+        inputStream = wrapWithGzip(inputStream);
       }
 
       reader = new BufferedReader(new InputStreamReader(inputStream),
@@ -253,6 +254,23 @@
     return reader;
   }
 
+  /**
+   * Wraps the provided stream for decompression, closing it if the wrapping fails so that the
+   * underlying file descriptor is not leaked.
+   */
+  private static InputStream wrapWithGzip(final InputStream inputStream) throws IOException
+  {
+    try
+    {
+      return new GZIPInputStream(inputStream);
+    }
+    catch (IOException | RuntimeException e)
+    {
+      StaticUtils.close(inputStream);
+      throw e;
+    }
+  }
+
 
 
   /**
@@ -284,7 +302,7 @@
 
     if (isCompressed)
     {
-      inputStream = new GZIPInputStream(inputStream);
+      inputStream = wrapWithGzip(inputStream);
     }
 
     reader = new BufferedReader(new InputStreamReader(inputStream), bufferSize);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/RecordingInputStream.java b/opendj-server-legacy/src/main/java/org/opends/server/types/RecordingInputStream.java
index bdc88bc..c841596 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/RecordingInputStream.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/RecordingInputStream.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2014-2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.types;
 
@@ -99,13 +100,13 @@
 
   /** {@inheritDoc} */
   @Override
-  public void mark(int i) {
+  public synchronized void mark(int i) {
     parentStream.mark(i);
   }
 
   /** {@inheritDoc} */
   @Override
-  public void reset() throws IOException {
+  public synchronized void reset() throws IOException {
     parentStream.reset();
   }
 
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JebTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JebTestCase.java
index b8eddcc..914e6c5 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JebTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JebTestCase.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.backends.jeb;
 
@@ -65,7 +66,7 @@
         ArrayList<LocalizableMessage> warnings = new ArrayList<>();
         templateFile.parse(template, warnings);
         MakeLDIFInputStream ldifEntryStream =
-            new MakeLDIFInputStream(templateFile);
+            MakeLDIFInputStream.newStartedInputStream(templateFile);
         LDIFReader reader =
             new LDIFReader(new LDIFImportConfig(ldifEntryStream));
         for(int i =0; i<numEntries;i++) {

--
Gitblit v1.10.0