From f9e749ec1f67c9a0b894a0c124bf262e54cfbbc4 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 02 Apr 2026 09:07:21 +0000
Subject: [PATCH] Merge branch 'master' into copilot/fix-dostopapplication-infinite-loop

---
 opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java      |   22 ++++++++++-
 opendj-server-legacy/src/build-tools/windows/service.c                                      |   46 +++++++++++++++++++---
 opendj-server-legacy/src/test/java/org/opends/server/tasks/LockdownModeTaskTestCase.java    |    5 +-
 opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java |    6 ++-
 opendj-server-legacy/lib/launcher_administrator.exe                                         |    0 
 .github/workflows/build.yml                                                                 |    1 
 opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LdapMessages.java                   |    8 ++++
 opendj-server-legacy/lib/opendj_service.exe                                                 |    0 
 opendj-server-legacy/lib/winlauncher.exe                                                    |    0 
 opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java          |    8 +++
 opendj-server-legacy/tests/unit-tests-testng/resource/config-changes.ldif                   |    6 +++
 11 files changed, 88 insertions(+), 14 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9123cd5..17a6361 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,6 +2,7 @@
 
 on:
   push:
+    branches: [ 'sustaining/4.10.x','master' ]
   pull_request:
     branches: [ 'sustaining/4.10.x','master' ]
 
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LdapMessages.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LdapMessages.java
index b4603a2..9dfab41 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LdapMessages.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LdapMessages.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.ldap.spi;
 
@@ -106,6 +107,13 @@
         private LdapResponseMessage(final byte messageType, final int messageId, final Response content) {
             super(messageType, messageId, content);
         }
+
+        @Override
+        public String toString() {
+            return "LdapResponseMessage(messageType=" + getMessageType()
+                    + ", messageId=" + getMessageId()
+                    + ", content=" + getContent() + ")";
+        }
     }
 
     private static abstract class LdapMessageEnvelope<T> {
diff --git a/opendj-server-legacy/lib/launcher_administrator.exe b/opendj-server-legacy/lib/launcher_administrator.exe
index 303839e..bf71337 100644
--- a/opendj-server-legacy/lib/launcher_administrator.exe
+++ b/opendj-server-legacy/lib/launcher_administrator.exe
Binary files differ
diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe
index 55b8da6..e4f456c 100644
--- a/opendj-server-legacy/lib/opendj_service.exe
+++ b/opendj-server-legacy/lib/opendj_service.exe
Binary files differ
diff --git a/opendj-server-legacy/lib/winlauncher.exe b/opendj-server-legacy/lib/winlauncher.exe
index 3a96c39..f971e1b 100755
--- a/opendj-server-legacy/lib/winlauncher.exe
+++ b/opendj-server-legacy/lib/winlauncher.exe
Binary files differ
diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c
index 58fc630..166853b 100644
--- a/opendj-server-legacy/src/build-tools/windows/service.c
+++ b/opendj-server-legacy/src/build-tools/windows/service.c
@@ -13,7 +13,7 @@
  *
  * Copyright 2008-2010 Sun Microsystems, Inc.
  * Portions Copyright 2011-2013 ForgeRock AS.
- * Portions copyright 2026 3A Systems, LLC
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 #include "service.h"
@@ -564,12 +564,44 @@
 
   if (createOk && waitOk)
     {
-    BOOL running;
-      // Just check once if the server is running or not: since the wait
-      // wait was successful, if the server is getting the lock, it already
-      // got it.
-    isServerRunning(&running, TRUE);
-    if (running)
+      // The batch file process completed successfully, but the Java server
+      // process may not have acquired the lock file yet (especially on
+      // Windows 11 where JVM startup can be slower). Retry with a loop
+      // similar to the else-if branch below.
+      // See: https://github.com/OpenIdentityPlatform/OpenDJ/issues/259
+      const DWORD DEFAULT_TRIES = 100;
+      int nTries = DEFAULT_TRIES;
+      char * nTriesEnv = getenv("OPENDJ_WINDOWS_SERVICE_START_NTRIES");
+      BOOL running = FALSE;
+      if (nTriesEnv != NULL)
+      {
+        debug("OPENDJ_WINDOWS_SERVICE_START_NTRIES env var set to %s", nTriesEnv);
+        nTries = (int)strtol(nTriesEnv, (char **)NULL, 10);
+        if (nTries <= 0)
+        {
+          nTries = DEFAULT_TRIES;
+        }
+      }
+      else
+      {
+        debug("OPENDJ_WINDOWS_SERVICE_START_NTRIES is not set.  Using default %d tries.", nTries);
+      }
+
+      while ((nTries > 0) && !running)
+      {
+        nTries--;
+        if (isServerRunning(&running, TRUE) != SERVICE_RETURN_OK)
+        {
+          break;
+        }
+        if (!running)
+        {
+          debug("Sleeping for 5 seconds to allow the process to get the lock.  %d tries remaining.",
+              nTries);
+          Sleep(5000);
+        }
+      }
+      if (running)
       {
         returnValue = SERVICE_RETURN_OK;
         debug("doStartApplication: server running.");
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
index 7bfe1ef..66b0be2 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.core;
 
@@ -109,8 +110,13 @@
       {
         SLF4JBridgeHandler.removeHandlersForRootLogger();
         // This is needed to avoid major performance issue. See: http://www.slf4j.org/legacy.html#jul-to-slf4j
+        // Limit Grizzly JUL logging to FINE to prevent a ClassCastException in
+        // FilterChainContext.toString() (Grizzly bug) when debug logging is enabled.
+        // Grizzly 3.0.1 DefaultFilterChain.executeFilter() checks isLoggable(FINEST) but
+        // its FilterChainContext.toString() incorrectly casts the message to char[].
         LogManager.getLogManager().readConfiguration(
-                new ByteArrayInputStream((".level=" + newLevel).getBytes()));
+                new ByteArrayInputStream(
+                        (".level=" + newLevel + "\norg.glassfish.grizzly.level=FINE").getBytes()));
         SLF4JBridgeHandler.install();
         currentJulLogLevel = newLevel;
       }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java
index 0d0157a..c435148 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java
@@ -590,6 +590,8 @@
     // write 4 more changes starting from changenumber 5, and search them
     testName = "Multiple/5";
     csns = generateAndPublishUpdateMsgForEachOperationType(testName, false);
+    // Wait until all 8 changes are indexed before searching
+    assertChangelogAttributesInRootDSE(1, 8);
     searchChangesForEachOperationTypeUsingChangeNumberMode(5, csns, testName);
 
     // search from the provided change number: 6 (should be the add msg)
@@ -1118,8 +1120,8 @@
       final ResultCode expectedResultCode, String testName) throws Exception
   {
     TestTimer timer = new TestTimer.Builder()
-      .maxSleep(10, SECONDS)
-      .sleepTimes(10, MILLISECONDS)
+      .maxSleep(30, SECONDS)
+      .sleepTimes(100, MILLISECONDS)
       .toTimer();
     InternalSearchOperation searchOp = timer.repeatUntilSuccess(new Callable<InternalSearchOperation>()
     {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
index b452ce0..84c9b1b 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
@@ -921,7 +921,7 @@
       replServer3 = createReplicationServer(replServerId3, true, testCase);
 
       connectServer1ToReplServer(replServer1);
-      Thread.sleep(2000); //wait for all RS handshakes to complete
+      waitForDomainsOnAllReplicationServers();
 
       debugInfo("Expect genId are set in all replServers.");
       waitForStableGenerationId(EMPTY_DN_GENID);
@@ -990,7 +990,7 @@
     }
   }
 
-  private void waitForStableGenerationId(final long expectedGenId) throws Exception
+  private void waitForDomainsOnAllReplicationServers() throws Exception
   {
     TestTimer timer = new TestTimer.Builder()
       .maxSleep(30, SECONDS)
@@ -1001,6 +1001,24 @@
       @Override
       public void call() throws Exception
       {
+        assertNotNull(replServer1.getReplicationServerDomain(baseDN), "domain missing on replServer1");
+        assertNotNull(replServer2.getReplicationServerDomain(baseDN), "domain missing on replServer2");
+        assertNotNull(replServer3.getReplicationServerDomain(baseDN), "domain missing on replServer3");
+      }
+    });
+  }
+
+  private void waitForStableGenerationId(final long expectedGenId) throws Exception
+  {
+    TestTimer timer = new TestTimer.Builder()
+      .maxSleep(60, SECONDS)
+      .sleepTimes(100, MILLISECONDS)
+      .toTimer();
+    timer.repeatUntilSuccess(new CallableVoid()
+    {
+      @Override
+      public void call() throws Exception
+      {
         assertGenIdEquals(expectedGenId);
       }
     });
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/tasks/LockdownModeTaskTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/tasks/LockdownModeTaskTestCase.java
index 18c087a..918acc4 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/tasks/LockdownModeTaskTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/tasks/LockdownModeTaskTestCase.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.tasks;
 
@@ -92,7 +93,7 @@
     boolean isLoopback = localAddress.isLoopbackAddress();
     String[] args =
     {
-      "-h", localIP,
+      "-h", "127.0.0.1",
       "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
       "-b", "",
       "-s", "base",
@@ -263,7 +264,7 @@
     // anonymous connection.
     args = new String[]
     {
-      "-h", localIP,
+      "-h", "127.0.0.1",
       "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
       "-b", "",
       "-s", "base",
diff --git a/opendj-server-legacy/tests/unit-tests-testng/resource/config-changes.ldif b/opendj-server-legacy/tests/unit-tests-testng/resource/config-changes.ldif
index cbf7a86..4f95eb3 100644
--- a/opendj-server-legacy/tests/unit-tests-testng/resource/config-changes.ldif
+++ b/opendj-server-legacy/tests/unit-tests-testng/resource/config-changes.ldif
@@ -11,6 +11,7 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2016 ForgeRock AS.
+# Portions Copyright 2026 3A Systems LLC.
 dn: cn=config
 changetype: modify
 replace: ds-cfg-notify-abandoned-operations
@@ -1610,3 +1611,8 @@
 -
 replace: ds-cfg-default-throwable-stack-frames
 ds-cfg-default-throwable-stack-frames: 500
+
+dn: cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config
+changetype: modify
+replace: ds-cfg-connection-timeout
+ds-cfg-connection-timeout: 30000 ms
\ No newline at end of file

--
Gitblit v1.10.0