diff --git a/ZA.CoreService.ESBCertificateManager/Form1.cs b/ZA.CoreService.ESBCertificateManager/Form1.cs
index a2809db..ede2546 100644
--- a/ZA.CoreService.ESBCertificateManager/Form1.cs
+++ b/ZA.CoreService.ESBCertificateManager/Form1.cs
@@ -1781,11 +1781,6 @@ namespace ZA.CoreService.ESBCertificateManager
cmbSonicConnection.Items.Add(conn.Name);
}
- if (cmbSonicConnection.Items.Count > 0)
- {
- cmbSonicConnection.SelectedIndex = 0;
- }
-
btnLoadFromSonic = CreateSecondaryButton("Container laden");
btnLoadFromSonic.Location = new Point(392, 103);
btnLoadFromSonic.Size = new Size(148, 28);
@@ -1797,20 +1792,19 @@ namespace ZA.CoreService.ESBCertificateManager
ForeColor = MutedTextColor,
Font = new Font("Segoe UI", 8.5f),
AutoSize = true,
- Location = new Point(552, 109)
+ MaximumSize = new Size(720, 0),
+ Location = new Point(552, 100)
};
- if (!_sonicDiscovery.HasConnections)
+ cmbSonicConnection.SelectedIndexChanged += (_, _) => RefreshSonicStatusLine();
+
+ if (cmbSonicConnection.Items.Count > 0)
{
- lblSonicStatus.Text = "Keine Sonic-Verbindung in appsettings konfiguriert";
- lblSonicStatus.ForeColor = RedColor;
+ cmbSonicConnection.SelectedIndex = 0;
}
else
{
- SonicConnection first = _sonicDiscovery.Connections[0];
- lblSonicStatus.Text =
- $"{_sonicDiscovery.Connections.Count} Verb. | {first.ManagementModeDisplay} | {first.DomainName} | {first.ConnectionUrl}";
- lblSonicStatus.ForeColor = GreenColor;
+ RefreshSonicStatusLine();
}
card.Controls.Add(sonicLabel);
@@ -1819,6 +1813,44 @@ namespace ZA.CoreService.ESBCertificateManager
card.Controls.Add(lblSonicStatus);
}
+ private void RefreshSonicStatusLine(string? suffix = null)
+ {
+ if (!_sonicDiscovery.HasConnections)
+ {
+ lblSonicStatus.Text = "Keine Sonic-Verbindung in appsettings konfiguriert";
+ lblSonicStatus.ForeColor = RedColor;
+ return;
+ }
+
+ string? selectedName = cmbSonicConnection?.SelectedItem?.ToString();
+ SonicConnection conn = _sonicDiscovery.Connections
+ .FirstOrDefault(c => string.Equals(c.Name, selectedName, StringComparison.OrdinalIgnoreCase))
+ ?? _sonicDiscovery.Connections[0];
+
+ (string sonicHome, string? javaExe) = new SonicMfApiExecutor(conn).ResolveRuntimePaths();
+ string javaDisplay = string.IsNullOrWhiteSpace(javaExe) ? "java=?" : javaExe;
+ string baseText =
+ $"{conn.ManagementModeDisplay} | SonicHome={sonicHome} | {javaDisplay}";
+ if (!string.IsNullOrWhiteSpace(suffix))
+ {
+ baseText = $"{suffix} | {baseText}";
+ }
+
+ lblSonicStatus.Text = baseText;
+ lblSonicStatus.ForeColor = string.IsNullOrWhiteSpace(javaExe) ? GoldColor : GreenColor;
+ }
+
+ private static string TruncateStatus(string? text, int max = 120)
+ {
+ if (string.IsNullOrWhiteSpace(text))
+ {
+ return "unbekannt";
+ }
+
+ string oneLine = text.Replace('\r', ' ').Replace('\n', ' ').Trim();
+ return oneLine.Length <= max ? oneLine : oneLine[..max] + "…";
+ }
+
private async Task LoadFromSonicAsync()
{
if (_isOperationRunning) return;
@@ -1840,7 +1872,7 @@ namespace ZA.CoreService.ESBCertificateManager
if (!result.Success)
{
- lblSonicStatus.Text = $"Fehler: {result.ErrorMessage}";
+ RefreshSonicStatusLine($"Fehler: {TruncateStatus(result.ErrorMessage)}");
lblSonicStatus.ForeColor = RedColor;
SetStatus($"Sonic-Discovery fehlgeschlagen: {result.ErrorMessage}", isError: true);
return;
@@ -1858,7 +1890,7 @@ namespace ZA.CoreService.ESBCertificateManager
if (total == 0)
{
- lblSonicStatus.Text = $"Verb. ok – 0 Container in Domain '{domain}'";
+ RefreshSonicStatusLine($"Verb. ok – 0 Container '{domain}'");
lblSonicStatus.ForeColor = GoldColor;
SetStatus(
result.ErrorMessage
@@ -1867,7 +1899,7 @@ namespace ZA.CoreService.ESBCertificateManager
}
else if (remote == 0)
{
- lblSonicStatus.Text = $"Verb. ok – Domain '{domain}': 0 remote, {total} aus Config";
+ RefreshSonicStatusLine($"Verb. ok – 0 remote, {total} Config '{domain}'");
lblSonicStatus.ForeColor = GoldColor;
SetStatus(
$"Domain '{domain}': Remote leer – {total} Ziel(e) aus appsettings/KnownContainers. "
@@ -1876,8 +1908,7 @@ namespace ZA.CoreService.ESBCertificateManager
}
else
{
- lblSonicStatus.Text = $"Domain '{domain}': {remote} remote, {total} gesamt";
- lblSonicStatus.ForeColor = GreenColor;
+ RefreshSonicStatusLine($"Domain '{domain}': {remote} remote, {total} gesamt");
SetStatus($"Sonic Domain '{domain}': {total} Ziel(e) geladen ({remote} remote).", isError: false);
}
@@ -1885,13 +1916,13 @@ namespace ZA.CoreService.ESBCertificateManager
}
catch (OperationCanceledException)
{
- lblSonicStatus.Text = "Timeout – Verbindung nicht erreichbar";
+ RefreshSonicStatusLine("Timeout");
lblSonicStatus.ForeColor = RedColor;
SetStatus($"Sonic-Discovery Timeout ({selectedConnection})", isError: true);
}
catch (Exception ex)
{
- lblSonicStatus.Text = $"Fehler: {ex.Message}";
+ RefreshSonicStatusLine($"Fehler: {TruncateStatus(ex.Message)}");
lblSonicStatus.ForeColor = RedColor;
SetStatus($"Sonic-Discovery Fehler: {ex.Message}", isError: true);
}
diff --git a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
index d9fad35..e85fadc 100644
--- a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
+++ b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
@@ -127,12 +127,15 @@ public sealed class SonicConnection
return false;
}
- /// Sonic-Installationsroot, z.B. "C:\Sonic\MQ10.0" (enthält lib\*.jar für MfApi).
+ ///
+ /// Sonic-/MQ-/ESB-Installationsroot, z.B. "C:\Sonic\MQ10.0" (Client-JARs oft unter lib).
+ /// Bei ESB-Home: ggf. MfClientLibPath auf MQ\lib setzen.
+ ///
public string SonicHome { get; init; } = @"C:\Sonic\MQ10.0";
///
/// Optional: JRE/JDK-Home (z.B. C:\Sonic\MQ10.0\jre) oder Pfad zu java.exe.
- /// Leer = automatische Suche (JAVA_HOME, PATH, SonicHome\jre, Program Files\…).
+ /// Leer = automatische Suche (JAVA_HOME/JRE_HOME, setenv.bat, rekursiv unter SonicHome, Registry, …).
///
public string JavaHome { get; init; } = string.Empty;
@@ -143,7 +146,7 @@ public sealed class SonicConnection
///
/// Optionaler Pfad zu Sonic-Client-JARs für MfApi (mgmt_client.jar etc.).
- /// Leer = SonicHome\lib.
+ /// Leer = SonicHome\lib, MQ_HOME\lib, ESB_HOME\lib bzw. nested MQ*/lib.
///
public string MfClientLibPath { get; init; } = string.Empty;
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
index 0984f6d..17cd4fd 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
@@ -1,5 +1,7 @@
using System.Diagnostics;
using System.Text;
+using System.Text.RegularExpressions;
+using Microsoft.Win32;
using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
@@ -12,6 +14,10 @@ namespace ZA.CoreService.ESBCertificateManager.Services;
///
public sealed class SonicMfApiExecutor
{
+ private const int MaxJavaSearchDepth = 6;
+ private const int MaxJavaFilesToScan = 80;
+ private const int MaxCheckedPathsInError = 40;
+
private readonly SonicConnection _connection;
public SonicMfApiExecutor(SonicConnection connection)
@@ -19,6 +25,19 @@ public sealed class SonicMfApiExecutor
_connection = connection;
}
+ ///
+ /// Liefert den konfigurierten SonicHome-Pfad und die gefundene java.exe (oder null).
+ /// Für UI-Status und Diagnose.
+ ///
+ public (string SonicHome, string? JavaExe) ResolveRuntimePaths()
+ {
+ JavaDiscoveryResult result = DiscoverJava();
+ string sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
+ ? "(leer)"
+ : _connection.SonicHome.Trim();
+ return (sonicHome, result.JavaExe);
+ }
+
public Task<(bool Success, string? Error)> TestConnectionAsync(CancellationToken cancellationToken = default)
=> RunAsync("ping", container: null, cancellationToken);
@@ -159,17 +178,30 @@ public sealed class SonicMfApiExecutor
private async Task<(bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error)>
PrepareToolAsync(CancellationToken cancellationToken)
{
- string? javaExe = ResolveJavaExecutable();
+ JavaDiscoveryResult javaResult = DiscoverJava();
+ string? javaExe = javaResult.JavaExe;
if (javaExe is null)
{
- string sonicHint = string.IsNullOrWhiteSpace(_connection.SonicHome)
- ? ""
- : $" Erwartet z.B. '{Path.Combine(_connection.SonicHome, "jre", "bin", "java.exe")}'.";
+ string sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
+ ? "(SonicHome leer / nicht gesetzt)"
+ : _connection.SonicHome.Trim();
+ string checkedList = javaResult.CheckedPaths.Count == 0
+ ? "(keine Kandidaten gesammelt)"
+ : string.Join("\n - ", javaResult.CheckedPaths.Take(MaxCheckedPathsInError));
+ if (javaResult.CheckedPaths.Count > MaxCheckedPathsInError)
+ {
+ checkedList += $"\n - … (+{javaResult.CheckedPaths.Count - MaxCheckedPathsInError} weitere)";
+ }
+
return (false, null, null, null,
- "Java nicht gefunden. Gesucht: SonicConnection.JavaHome/JavaPath, JAVA_HOME, PATH, " +
- "SonicHome\\jre|jdk\\bin\\java.exe, Program Files\\Java|Eclipse Adoptium." +
- sonicHint +
- " Für MfApi JavaHome in appsettings setzen oder JRE unter SonicHome nutzen.");
+ "Java nicht gefunden.\n" +
+ $"Verwendetes SonicHome: '{sonicHome}'\n" +
+ $"SonicHome existiert: {(Directory.Exists(sonicHome) ? "ja" : "nein")}\n" +
+ "Konfiguration: SonicConnection.JavaHome / JavaPath, sonst Auto-Suche " +
+ "(JAVA_HOME/JRE_HOME, setenv.bat, rekursiv unter SonicHome, MQ/ESB-Nachbarn, Registry, where).\n" +
+ "Geprüfte Pfade:\n - " + checkedList + "\n" +
+ "Tipp: JavaHome oder JavaPath in appsettings auf die echte java.exe setzen " +
+ "(z.B. C:\\Sonic\\MQ10.0\\jre\\bin\\java.exe).");
}
(string? libDir, string? libError) = ResolveLibDirectoryDetailed();
@@ -295,59 +327,184 @@ public sealed class SonicMfApiExecutor
if (!string.IsNullOrWhiteSpace(_connection.MfClientLibPath))
{
- candidates.Add((_connection.MfClientLibPath, "MfClientLibPath"));
+ candidates.Add((_connection.MfClientLibPath.Trim(), "MfClientLibPath"));
+ }
+
+ string? mqHome = Environment.GetEnvironmentVariable("MQ_HOME");
+ string? esbHome = Environment.GetEnvironmentVariable("ESB_HOME")
+ ?? Environment.GetEnvironmentVariable("SONIC_HOME")
+ ?? Environment.GetEnvironmentVariable("SONICMQ_HOME");
+
+ if (!string.IsNullOrWhiteSpace(mqHome))
+ {
+ candidates.Add((Path.Combine(mqHome.Trim().Trim('"'), "lib"), "MQ_HOME\\lib"));
+ }
+
+ if (!string.IsNullOrWhiteSpace(esbHome))
+ {
+ string esb = esbHome.Trim().Trim('"');
+ candidates.Add((Path.Combine(esb, "lib"), "ESB_HOME\\lib"));
+ candidates.Add((Path.Combine(esb, "MQ", "lib"), "ESB_HOME\\MQ\\lib"));
+ candidates.Add((Path.Combine(esb, "mq", "lib"), "ESB_HOME\\mq\\lib"));
}
if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
{
- candidates.Add((Path.Combine(_connection.SonicHome, "lib"), "SonicHome\\lib"));
- candidates.Add((_connection.SonicHome, "SonicHome"));
+ string sonicHome = _connection.SonicHome.Trim();
+ candidates.Add((Path.Combine(sonicHome, "lib"), "SonicHome\\lib"));
+ candidates.Add((sonicHome, "SonicHome"));
+
+ // ESB-Home zeigt oft auf Broker/ESB; Client-JARs liegen unter MQ*/lib oder sibling MQ.
+ foreach (string nested in EnumerateLikelyLibRoots(sonicHome))
+ {
+ candidates.Add((nested, "SonicHome-nested\\lib"));
+ }
+
+ string? parent = Directory.GetParent(sonicHome)?.FullName;
+ if (!string.IsNullOrWhiteSpace(parent))
+ {
+ candidates.Add((Path.Combine(parent, "lib"), "SonicHome-Parent\\lib"));
+ foreach (string nested in EnumerateLikelyLibRoots(parent))
+ {
+ candidates.Add((nested, "SonicHome-Parent-nested\\lib"));
+ }
+ }
}
List checkedPaths = [];
+ HashSet seen = new(StringComparer.OrdinalIgnoreCase);
foreach ((string path, string label) in candidates)
{
+ if (string.IsNullOrWhiteSpace(path) || !seen.Add(path))
+ {
+ continue;
+ }
+
checkedPaths.Add($"{label}='{path}'");
if (!Directory.Exists(path))
{
continue;
}
- if (Directory.EnumerateFiles(path, "*.jar", SearchOption.TopDirectoryOnly).Any())
+ if (DirectoryHasSonicClientJars(path))
{
return (path, null);
}
}
- string sonicHome = _connection.SonicHome ?? string.Empty;
- bool sonicHomeExists = !string.IsNullOrWhiteSpace(sonicHome) && Directory.Exists(sonicHome);
- string libPath = string.IsNullOrWhiteSpace(sonicHome)
+ string sonicHomeVal = _connection.SonicHome ?? string.Empty;
+ bool sonicHomeExists = !string.IsNullOrWhiteSpace(sonicHomeVal) && Directory.Exists(sonicHomeVal);
+ string libPath = string.IsNullOrWhiteSpace(sonicHomeVal)
? "(SonicHome leer)"
- : Path.Combine(sonicHome, "lib");
+ : Path.Combine(sonicHomeVal, "lib");
if (sonicHomeExists && Directory.Exists(libPath)
&& !Directory.EnumerateFiles(libPath, "*.jar", SearchOption.TopDirectoryOnly).Any())
{
return (null,
- $"Sonic-Client-JARs fehlen unter '{libPath}' (Ordner existiert, aber keine *.jar). " +
- "MfApi braucht u.a. mgmt_client.jar / mfcontext.jar / sonic_Client.jar. " +
- "MfClientLibPath auf den korrekten Lib-Ordner setzen.");
+ $"Sonic-Client-JARs fehlen unter '{libPath}' (Ordner existiert, aber keine *.jar).\n" +
+ $"Verwendetes SonicHome: '{sonicHomeVal}'\n" +
+ "MfApi braucht u.a. mgmt_client.jar / mfcontext.jar / sonic_Client.jar.\n" +
+ "Falls SonicHome auf ESB zeigt: auf MQ-Home setzen oder MfClientLibPath auf den MQ\\lib-Ordner.\n" +
+ $"Geprüft: {string.Join("; ", checkedPaths)}");
}
if (sonicHomeExists && !Directory.Exists(libPath))
{
return (null,
- $"SonicHome='{sonicHome}' gefunden, aber Lib-Ordner fehlt: '{libPath}'. " +
+ $"SonicHome='{sonicHomeVal}' gefunden, aber Lib-Ordner fehlt: '{libPath}'.\n" +
"Sonic-Client-Installation prüfen oder MfClientLibPath setzen " +
- "(erwartet *.jar, u.a. mgmt_client.jar).");
+ "(erwartet *.jar, u.a. mgmt_client.jar).\n" +
+ $"Geprüft: {string.Join("; ", checkedPaths)}");
}
return (null,
- "Sonic-Client-JARs nicht gefunden. SonicHome\\lib oder MfClientLibPath setzen " +
- $"(geprüft: {string.Join("; ", checkedPaths)}). " +
+ "Sonic-Client-JARs nicht gefunden. SonicHome\\lib, MQ_HOME\\lib, ESB_HOME\\lib oder MfClientLibPath setzen.\n" +
+ $"Verwendetes SonicHome: '{(string.IsNullOrWhiteSpace(sonicHomeVal) ? "(leer)" : sonicHomeVal)}'\n" +
+ $"Geprüft:\n - {string.Join("\n - ", checkedPaths)}\n" +
"Benötigt u.a. mgmt_client.jar / mfcontext.jar / sonic_Client.jar.");
}
+ private static IEnumerable EnumerateLikelyLibRoots(string root)
+ {
+ if (!Directory.Exists(root))
+ {
+ yield break;
+ }
+
+ string[] preferred =
+ [
+ Path.Combine(root, "MQ", "lib"),
+ Path.Combine(root, "mq", "lib"),
+ Path.Combine(root, "ESB", "lib"),
+ Path.Combine(root, "esb", "lib"),
+ Path.Combine(root, "client", "lib"),
+ Path.Combine(root, "Client", "lib")
+ ];
+
+ foreach (string path in preferred)
+ {
+ if (Directory.Exists(path))
+ {
+ yield return path;
+ }
+ }
+
+ IEnumerable children;
+ try
+ {
+ children = Directory.EnumerateDirectories(root);
+ }
+ catch
+ {
+ yield break;
+ }
+
+ foreach (string child in children)
+ {
+ string name = Path.GetFileName(child);
+ if (name.StartsWith("MQ", StringComparison.OrdinalIgnoreCase)
+ || name.StartsWith("ESB", StringComparison.OrdinalIgnoreCase)
+ || name.Contains("Sonic", StringComparison.OrdinalIgnoreCase))
+ {
+ string lib = Path.Combine(child, "lib");
+ if (Directory.Exists(lib))
+ {
+ yield return lib;
+ }
+ }
+ }
+ }
+
+ private static bool DirectoryHasSonicClientJars(string path)
+ {
+ try
+ {
+ string[] jars = Directory.EnumerateFiles(path, "*.jar", SearchOption.TopDirectoryOnly).ToArray();
+ if (jars.Length == 0)
+ {
+ return false;
+ }
+
+ // Bevorzugt echte Sonic-Client-Libs; sonst jeder JAR-Ordner als Fallback.
+ string[] markers =
+ [
+ "mgmt_client", "mfcontext", "sonic_Client", "sonic_client", "mf_client", "Sonic"
+ ];
+ if (jars.Any(j => markers.Any(m =>
+ Path.GetFileName(j).Contains(m, StringComparison.OrdinalIgnoreCase))))
+ {
+ return true;
+ }
+
+ return jars.Length > 0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
private static string BuildClasspath(string libDir, string? extraEntry)
{
// Java-Classpath-Wildcard für alle JARs im Lib-Ordner
@@ -369,62 +526,151 @@ public sealed class SonicMfApiExecutor
return candidates.FirstOrDefault(File.Exists);
}
- private string? ResolveJavaExecutable()
+ private sealed class JavaDiscoveryResult
{
+ public string? JavaExe { get; set; }
+ public List CheckedPaths { get; } = [];
+ }
+
+ private string? ResolveJavaExecutable() => DiscoverJava().JavaExe;
+
+ private JavaDiscoveryResult DiscoverJava()
+ {
+ JavaDiscoveryResult result = new();
+ List checkedPaths = result.CheckedPaths;
+
foreach (string? configured in new[] { _connection.JavaPath, _connection.JavaHome })
{
- string? fromConfig = ResolveJavaFromConfiguredPath(configured);
+ if (string.IsNullOrWhiteSpace(configured))
+ {
+ continue;
+ }
+
+ string? fromConfig = ResolveToolFromConfiguredPath(configured, JavaExeName, checkedPaths);
if (fromConfig is not null)
{
- return fromConfig;
+ result.JavaExe = fromConfig;
+ return result;
}
}
- string? javaHome = Environment.GetEnvironmentVariable("JAVA_HOME");
- string? fromEnv = ResolveJavaFromHomeDir(javaHome);
- if (fromEnv is not null)
+ foreach (string envName in new[] { "JAVA_HOME", "JRE_HOME", "JDK_HOME" })
{
- return fromEnv;
+ string? home = Environment.GetEnvironmentVariable(envName);
+ string? fromEnv = ResolveJavaFromHomeDir(home, checkedPaths, envName);
+ if (fromEnv is not null)
+ {
+ result.JavaExe = fromEnv;
+ return result;
+ }
}
- string? fromPath = FindOnPath(JavaExeName) ?? FindOnPath("java");
+ string? fromPath = FindOnPath(JavaExeName, checkedPaths) ?? FindOnPath("java", checkedPaths);
if (fromPath is not null)
{
- return fromPath;
+ result.JavaExe = fromPath;
+ return result;
}
- if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
+ string? sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
+ ? null
+ : _connection.SonicHome.Trim();
+
+ if (!string.IsNullOrWhiteSpace(sonicHome))
{
- string sonicHome = _connection.SonicHome;
- string[] direct =
- [
- Path.Combine(sonicHome, "jre", "bin", JavaExeName),
- Path.Combine(sonicHome, "jdk", "bin", JavaExeName),
- Path.Combine(sonicHome, "JRE", "bin", JavaExeName),
- Path.Combine(sonicHome, "JDK", "bin", JavaExeName)
- ];
- foreach (string candidate in direct)
+ string? fromScripts = FindJavaFromSonicScripts(sonicHome, checkedPaths);
+ if (fromScripts is not null)
{
- if (File.Exists(candidate))
- {
- return candidate;
- }
+ result.JavaExe = fromScripts;
+ return result;
}
- // Häufige Layouts: SonicHome\MQ*\jre, SonicHome\jre64, SonicHome\Java\jre, ...
- string? nested = FindJavaUnderSonicHome(sonicHome);
+ string? direct = TryKnownJavaLayouts(sonicHome, checkedPaths);
+ if (direct is not null)
+ {
+ result.JavaExe = direct;
+ return result;
+ }
+
+ string? nested = FindJavaUnderSonicHome(sonicHome, checkedPaths);
if (nested is not null)
{
- return nested;
+ result.JavaExe = nested;
+ return result;
+ }
+
+ string? recursive = FindJavaRecursive(sonicHome, checkedPaths, MaxJavaSearchDepth);
+ if (recursive is not null)
+ {
+ result.JavaExe = recursive;
+ return result;
+ }
+
+ // Parent / sibling MQ / ESB Layouts
+ string? parent = Directory.GetParent(sonicHome)?.FullName;
+ if (!string.IsNullOrWhiteSpace(parent))
+ {
+ string? fromParent = TryKnownJavaLayouts(parent, checkedPaths)
+ ?? FindJavaUnderSonicHome(parent, checkedPaths)
+ ?? FindJavaRecursive(parent, checkedPaths, depth: 3);
+ if (fromParent is not null)
+ {
+ result.JavaExe = fromParent;
+ return result;
+ }
+
+ foreach (string siblingRoot in EnumerateSiblingMqEsbRoots(parent, sonicHome))
+ {
+ string? fromSibling = TryKnownJavaLayouts(siblingRoot, checkedPaths)
+ ?? FindJavaUnderSonicHome(siblingRoot, checkedPaths);
+ if (fromSibling is not null)
+ {
+ result.JavaExe = fromSibling;
+ return result;
+ }
+ }
}
}
- return FindJavaInCommonInstallLocations();
+ foreach (string commonRoot in EnumerateCommonSonicRoots())
+ {
+ string? found = TryKnownJavaLayouts(commonRoot, checkedPaths)
+ ?? FindJavaUnderSonicHome(commonRoot, checkedPaths);
+ if (found is not null)
+ {
+ result.JavaExe = found;
+ return result;
+ }
+ }
+
+ string? fromRegistry = FindJavaInWindowsRegistry(checkedPaths);
+ if (fromRegistry is not null)
+ {
+ result.JavaExe = fromRegistry;
+ return result;
+ }
+
+ string? fromWhere = FindJavaViaWhereExe(checkedPaths);
+ if (fromWhere is not null)
+ {
+ result.JavaExe = fromWhere;
+ return result;
+ }
+
+ string? fromCommon = FindJavaInCommonInstallLocations(checkedPaths);
+ if (fromCommon is not null)
+ {
+ result.JavaExe = fromCommon;
+ return result;
+ }
+
+ return result;
}
private string? ResolveJavacExecutable(string javaExe)
{
string javacName = OperatingSystem.IsWindows() ? "javac.exe" : "javac";
+ List ignored = [];
string? dir = Path.GetDirectoryName(javaExe);
if (!string.IsNullOrWhiteSpace(dir))
@@ -438,20 +684,23 @@ public sealed class SonicMfApiExecutor
foreach (string? configured in new[] { _connection.JavaPath, _connection.JavaHome })
{
- string? fromConfig = ResolveToolFromConfiguredPath(configured, javacName);
+ string? fromConfig = ResolveToolFromConfiguredPath(configured, javacName, ignored);
if (fromConfig is not null)
{
return fromConfig;
}
}
- string? javaHome = Environment.GetEnvironmentVariable("JAVA_HOME");
- if (!string.IsNullOrWhiteSpace(javaHome))
+ foreach (string envName in new[] { "JAVA_HOME", "JDK_HOME" })
{
- string candidate = Path.Combine(javaHome, "bin", javacName);
- if (File.Exists(candidate))
+ string? javaHome = Environment.GetEnvironmentVariable(envName);
+ if (!string.IsNullOrWhiteSpace(javaHome))
{
- return candidate;
+ string candidate = Path.Combine(javaHome.Trim().Trim('"'), "bin", javacName);
+ if (File.Exists(candidate))
+ {
+ return candidate;
+ }
}
}
@@ -467,13 +716,13 @@ public sealed class SonicMfApiExecutor
}
}
- return FindOnPath(javacName) ?? FindOnPath("javac");
+ return FindOnPath(javacName, ignored) ?? FindOnPath("javac", ignored);
}
- private static string? ResolveJavaFromConfiguredPath(string? configured)
- => ResolveToolFromConfiguredPath(configured, JavaExeName);
-
- private static string? ResolveToolFromConfiguredPath(string? configured, string exeName)
+ private static string? ResolveToolFromConfiguredPath(
+ string? configured,
+ string exeName,
+ List checkedPaths)
{
if (string.IsNullOrWhiteSpace(configured))
{
@@ -481,6 +730,7 @@ public sealed class SonicMfApiExecutor
}
string path = configured.Trim().Trim('"');
+ NoteChecked(checkedPaths, $"config:{path}");
if (File.Exists(path))
{
@@ -489,18 +739,17 @@ public sealed class SonicMfApiExecutor
return path;
}
- // Konfiguriert: ...\bin\java.exe → sibling javac.exe (oder umgekehrt)
string? parent = Path.GetDirectoryName(path);
if (!string.IsNullOrWhiteSpace(parent))
{
string sibling = Path.Combine(parent, exeName);
+ NoteChecked(checkedPaths, sibling);
if (File.Exists(sibling))
{
return sibling;
}
}
- // java ohne Endung (Unix) oder exakter Treffer
string fileName = Path.GetFileName(path);
if (fileName.Equals(Path.GetFileNameWithoutExtension(exeName), StringComparison.OrdinalIgnoreCase)
|| fileName.Equals(exeName, StringComparison.OrdinalIgnoreCase))
@@ -510,31 +759,78 @@ public sealed class SonicMfApiExecutor
}
string fromHome = Path.Combine(path, "bin", exeName);
+ NoteChecked(checkedPaths, fromHome);
return File.Exists(fromHome) ? fromHome : null;
}
- private static string? ResolveJavaFromHomeDir(string? home)
+ private static string? ResolveJavaFromHomeDir(string? home, List checkedPaths, string label)
{
if (string.IsNullOrWhiteSpace(home))
{
+ NoteChecked(checkedPaths, $"{label}=(leer)");
return null;
}
- string candidate = Path.Combine(home.Trim().Trim('"'), "bin", JavaExeName);
- return File.Exists(candidate) ? candidate : null;
+ string trimmed = home.Trim().Trim('"');
+ string candidate = Path.Combine(trimmed, "bin", JavaExeName);
+ NoteChecked(checkedPaths, $"{label}:{candidate}");
+ if (File.Exists(candidate))
+ {
+ return candidate;
+ }
+
+ // Manchmal zeigt JAVA_HOME bereits auf ...\bin
+ string asBin = Path.Combine(trimmed, JavaExeName);
+ NoteChecked(checkedPaths, $"{label}:{asBin}");
+ return File.Exists(asBin) ? asBin : null;
}
- private static string? FindJavaUnderSonicHome(string sonicHome)
+ private static string? TryKnownJavaLayouts(string root, List checkedPaths)
+ {
+ if (string.IsNullOrWhiteSpace(root))
+ {
+ return null;
+ }
+
+ string[] relatives =
+ [
+ Path.Combine("jre", "bin", JavaExeName),
+ Path.Combine("jdk", "bin", JavaExeName),
+ Path.Combine("JRE", "bin", JavaExeName),
+ Path.Combine("JDK", "bin", JavaExeName),
+ Path.Combine("jre64", "bin", JavaExeName),
+ Path.Combine("jdk64", "bin", JavaExeName),
+ Path.Combine("Java", "jre", "bin", JavaExeName),
+ Path.Combine("Java", "jdk", "bin", JavaExeName),
+ Path.Combine("java", "bin", JavaExeName),
+ Path.Combine("bin", JavaExeName)
+ ];
+
+ foreach (string rel in relatives)
+ {
+ string candidate = Path.Combine(root, rel);
+ NoteChecked(checkedPaths, candidate);
+ if (File.Exists(candidate))
+ {
+ return candidate;
+ }
+ }
+
+ return null;
+ }
+
+ private static string? FindJavaUnderSonicHome(string sonicHome, List checkedPaths)
{
if (!Directory.Exists(sonicHome))
{
+ NoteChecked(checkedPaths, $"SonicHome-missing:{sonicHome}");
return null;
}
- // Direkte Unterordner mit jre/jdk
foreach (string root in EnumerateJdkRootsUnderSonicHome(sonicHome))
{
string candidate = Path.Combine(root, "bin", JavaExeName);
+ NoteChecked(checkedPaths, candidate);
if (File.Exists(candidate))
{
return candidate;
@@ -570,7 +866,6 @@ public sealed class SonicMfApiExecutor
}
}
- // {SonicHome}\*\jre und {SonicHome}\*\jdk
IEnumerable children;
try
{
@@ -583,7 +878,7 @@ public sealed class SonicMfApiExecutor
foreach (string child in children)
{
- foreach (string leaf in new[] { "jre", "jdk", "JRE", "JDK" })
+ foreach (string leaf in new[] { "jre", "jdk", "JRE", "JDK", "jre64", "jdk64" })
{
string nested = Path.Combine(child, leaf);
if (Directory.Exists(nested))
@@ -592,7 +887,6 @@ public sealed class SonicMfApiExecutor
}
}
- // z.B. ...\jre1.8.0_xxx direkt als Kind
string leafName = Path.GetFileName(child);
if (leafName.StartsWith("jre", StringComparison.OrdinalIgnoreCase)
|| leafName.StartsWith("jdk", StringComparison.OrdinalIgnoreCase))
@@ -602,7 +896,445 @@ public sealed class SonicMfApiExecutor
}
}
- private static string? FindJavaInCommonInstallLocations()
+ private static string? FindJavaFromSonicScripts(string sonicHome, List checkedPaths)
+ {
+ if (!Directory.Exists(sonicHome))
+ {
+ return null;
+ }
+
+ string[] scriptDirs =
+ [
+ Path.Combine(sonicHome, "bin"),
+ sonicHome,
+ Path.Combine(sonicHome, "MQ", "bin"),
+ Path.Combine(sonicHome, "mq", "bin")
+ ];
+
+ string[] scriptNames =
+ [
+ "setenv.bat", "setenv.sh", "setenv.cmd",
+ "sonic_env.bat", "sonic_env.sh", "sonic_env.cmd",
+ "startcontainer.bat", "startcontainer.sh",
+ "startmc.bat", "startmc.sh",
+ "startbroker.bat", "startbroker.sh"
+ ];
+
+ List scripts = [];
+ foreach (string dir in scriptDirs.Where(Directory.Exists))
+ {
+ foreach (string name in scriptNames)
+ {
+ string path = Path.Combine(dir, name);
+ if (File.Exists(path))
+ {
+ scripts.Add(path);
+ }
+ }
+
+ try
+ {
+ foreach (string path in Directory.EnumerateFiles(dir, "sonic_env*", SearchOption.TopDirectoryOnly))
+ {
+ scripts.Add(path);
+ }
+
+ foreach (string path in Directory.EnumerateFiles(dir, "setenv*", SearchOption.TopDirectoryOnly))
+ {
+ scripts.Add(path);
+ }
+ }
+ catch
+ {
+ // ignore
+ }
+ }
+
+ foreach (string script in scripts.Distinct(StringComparer.OrdinalIgnoreCase))
+ {
+ NoteChecked(checkedPaths, $"script:{script}");
+ string? found = ParseJavaFromEnvScript(script, sonicHome, checkedPaths);
+ if (found is not null)
+ {
+ return found;
+ }
+ }
+
+ return null;
+ }
+
+ private static string? ParseJavaFromEnvScript(string scriptPath, string sonicHome, List checkedPaths)
+ {
+ string text;
+ try
+ {
+ text = File.ReadAllText(scriptPath);
+ }
+ catch
+ {
+ return null;
+ }
+
+ // JAVA_HOME / JRE_HOME / JDK_HOME Assignments
+ Regex homeAssign = new(
+ @"(?im)(?:set\s+)?(?JAVA_HOME|JRE_HOME|JDK_HOME)\s*=\s*(?[^\r\n]+)");
+ foreach (Match match in homeAssign.Matches(text))
+ {
+ string raw = ExpandScriptPath(match.Groups["val"].Value, sonicHome);
+ string? resolved = ResolveJavaFromHomeDir(raw, checkedPaths, Path.GetFileName(scriptPath));
+ if (resolved is not null)
+ {
+ return resolved;
+ }
+ }
+
+ // Direkte java.exe-Pfade in Scripten
+ Regex javaExeRef = new(
+ @"(?i)(?(?:[A-Za-z]:\\|/)[^\s""']+?[/\\]java(?:\.exe)?)");
+ foreach (Match match in javaExeRef.Matches(text))
+ {
+ string raw = ExpandScriptPath(match.Groups["path"].Value, sonicHome);
+ NoteChecked(checkedPaths, $"script-java:{raw}");
+ if (File.Exists(raw))
+ {
+ return raw;
+ }
+ }
+
+ return null;
+ }
+
+ private static string ExpandScriptPath(string raw, string sonicHome)
+ {
+ string value = raw.Trim().Trim('"', '\'', '`');
+
+ // Zuerst Variablen expandieren, danach Rauschen (Kommentare/Operatoren) abschneiden.
+ value = Regex.Replace(value, "%~dp0", sonicHome + Path.DirectorySeparatorChar,
+ RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, "%SONIC_HOME%", sonicHome, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, "%MQ_HOME%",
+ Environment.GetEnvironmentVariable("MQ_HOME") ?? sonicHome, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, "%ESB_HOME%",
+ Environment.GetEnvironmentVariable("ESB_HOME") ?? sonicHome, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, "%JAVA_HOME%",
+ Environment.GetEnvironmentVariable("JAVA_HOME") ?? string.Empty, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, "%JRE_HOME%",
+ Environment.GetEnvironmentVariable("JRE_HOME") ?? string.Empty, RegexOptions.IgnoreCase);
+
+ value = Regex.Replace(value, @"\$\{?SONIC_HOME\}?", sonicHome, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, @"\$\{?MQ_HOME\}?",
+ Environment.GetEnvironmentVariable("MQ_HOME") ?? sonicHome, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, @"\$\{?JAVA_HOME\}?",
+ Environment.GetEnvironmentVariable("JAVA_HOME") ?? string.Empty, RegexOptions.IgnoreCase);
+ value = Regex.Replace(value, @"\$\{?JRE_HOME\}?",
+ Environment.GetEnvironmentVariable("JRE_HOME") ?? string.Empty, RegexOptions.IgnoreCase);
+
+ // trailing " & rem ..." / " && ..." entfernen
+ int cut = value.IndexOfAny(['&', '|', '>', '<', '`']);
+ if (cut >= 0)
+ {
+ value = value[..cut];
+ }
+
+ int rem = value.IndexOf(" rem ", StringComparison.OrdinalIgnoreCase);
+ if (rem >= 0)
+ {
+ value = value[..rem];
+ }
+
+ if (value.StartsWith('.') || value.StartsWith(".."))
+ {
+ try
+ {
+ value = Path.GetFullPath(Path.Combine(sonicHome, value));
+ }
+ catch
+ {
+ // keep as-is
+ }
+ }
+
+ return value.Trim().Trim('"', '\'');
+ }
+
+ private static string? FindJavaRecursive(string root, List checkedPaths, int depth)
+ {
+ if (!Directory.Exists(root) || depth < 1)
+ {
+ return null;
+ }
+
+ List preferred = [];
+ List others = [];
+ int scanned = 0;
+
+ void Walk(string dir, int remaining)
+ {
+ if (scanned >= MaxJavaFilesToScan || remaining < 0)
+ {
+ return;
+ }
+
+ try
+ {
+ string candidate = Path.Combine(dir, JavaExeName);
+ if (File.Exists(candidate))
+ {
+ scanned++;
+ string normalized = candidate.Replace('/', Path.DirectorySeparatorChar);
+ if (normalized.Contains($"{Path.DirectorySeparatorChar}jre{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}",
+ StringComparison.OrdinalIgnoreCase)
+ || normalized.Contains($"{Path.DirectorySeparatorChar}jdk{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}",
+ StringComparison.OrdinalIgnoreCase))
+ {
+ preferred.Add(candidate);
+ }
+ else
+ {
+ others.Add(candidate);
+ }
+ }
+
+ if (remaining == 0 || scanned >= MaxJavaFilesToScan)
+ {
+ return;
+ }
+
+ foreach (string child in Directory.EnumerateDirectories(dir))
+ {
+ string name = Path.GetFileName(child);
+ if (name.Equals("tmp", StringComparison.OrdinalIgnoreCase)
+ || name.Equals("temp", StringComparison.OrdinalIgnoreCase)
+ || name.Equals("logs", StringComparison.OrdinalIgnoreCase)
+ || name.Equals("log", StringComparison.OrdinalIgnoreCase)
+ || name.Equals(".git", StringComparison.OrdinalIgnoreCase)
+ || name.Equals("node_modules", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ Walk(child, remaining - 1);
+ if (scanned >= MaxJavaFilesToScan)
+ {
+ return;
+ }
+ }
+ }
+ catch
+ {
+ // inaccessible directory
+ }
+ }
+
+ Walk(root, depth);
+
+ string? best = preferred.FirstOrDefault() ?? others.FirstOrDefault();
+ if (best is not null)
+ {
+ NoteChecked(checkedPaths, $"recursive-hit:{best}");
+ return best;
+ }
+
+ NoteChecked(checkedPaths, $"recursive-miss:{root} (depth<={depth}, scanned={scanned})");
+ return null;
+ }
+
+ private static IEnumerable EnumerateSiblingMqEsbRoots(string parent, string currentSonicHome)
+ {
+ if (!Directory.Exists(parent))
+ {
+ yield break;
+ }
+
+ IEnumerable children;
+ try
+ {
+ children = Directory.EnumerateDirectories(parent);
+ }
+ catch
+ {
+ yield break;
+ }
+
+ foreach (string child in children)
+ {
+ if (string.Equals(child, currentSonicHome, StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ string name = Path.GetFileName(child);
+ if (name.StartsWith("MQ", StringComparison.OrdinalIgnoreCase)
+ || name.StartsWith("ESB", StringComparison.OrdinalIgnoreCase)
+ || name.Contains("Sonic", StringComparison.OrdinalIgnoreCase))
+ {
+ yield return child;
+ }
+ }
+ }
+
+ private static IEnumerable EnumerateCommonSonicRoots()
+ {
+ string[] roots =
+ [
+ @"C:\Sonic",
+ @"C:\Program Files\Progress",
+ @"C:\Program Files\Aurea",
+ @"C:\Program Files (x86)\Progress",
+ @"C:\Program Files (x86)\Aurea",
+ @"D:\Sonic",
+ Environment.GetEnvironmentVariable("MQ_HOME") ?? string.Empty,
+ Environment.GetEnvironmentVariable("ESB_HOME") ?? string.Empty,
+ Environment.GetEnvironmentVariable("SONIC_HOME") ?? string.Empty
+ ];
+
+ foreach (string root in roots.Where(r => !string.IsNullOrWhiteSpace(r)).Distinct(StringComparer.OrdinalIgnoreCase))
+ {
+ if (Directory.Exists(root))
+ {
+ yield return root;
+ }
+
+ string? parentExists = Directory.Exists(root) ? root : null;
+ if (parentExists is null)
+ {
+ continue;
+ }
+
+ IEnumerable children;
+ try
+ {
+ children = Directory.EnumerateDirectories(parentExists);
+ }
+ catch
+ {
+ continue;
+ }
+
+ foreach (string child in children)
+ {
+ string name = Path.GetFileName(child);
+ if (name.StartsWith("MQ", StringComparison.OrdinalIgnoreCase)
+ || name.StartsWith("ESB", StringComparison.OrdinalIgnoreCase)
+ || name.Contains("Sonic", StringComparison.OrdinalIgnoreCase))
+ {
+ yield return child;
+ }
+ }
+ }
+ }
+
+ private static string? FindJavaInWindowsRegistry(List checkedPaths)
+ {
+ if (!OperatingSystem.IsWindows())
+ {
+ return null;
+ }
+
+ string[] keyPaths =
+ [
+ @"SOFTWARE\JavaSoft\Java Runtime Environment",
+ @"SOFTWARE\JavaSoft\JDK",
+ @"SOFTWARE\JavaSoft\Java Development Kit",
+ @"SOFTWARE\Eclipse Adoptium\JRE",
+ @"SOFTWARE\Eclipse Adoptium\JDK",
+ @"SOFTWARE\WOW6432Node\JavaSoft\Java Runtime Environment",
+ @"SOFTWARE\WOW6432Node\JavaSoft\JDK"
+ ];
+
+ foreach (string keyPath in keyPaths)
+ {
+ try
+ {
+ using RegistryKey? baseKey = Registry.LocalMachine.OpenSubKey(keyPath);
+ if (baseKey is null)
+ {
+ NoteChecked(checkedPaths, $"registry-miss:HKLM\\{keyPath}");
+ continue;
+ }
+
+ NoteChecked(checkedPaths, $"registry:HKLM\\{keyPath}");
+
+ string? current = baseKey.GetValue("CurrentVersion") as string;
+ if (!string.IsNullOrWhiteSpace(current))
+ {
+ using RegistryKey? verKey = baseKey.OpenSubKey(current);
+ string? javaHome = verKey?.GetValue("JavaHome") as string;
+ string? resolved = ResolveJavaFromHomeDir(javaHome, checkedPaths, $"registry:{current}");
+ if (resolved is not null)
+ {
+ return resolved;
+ }
+ }
+
+ foreach (string subName in baseKey.GetSubKeyNames().OrderByDescending(s => s))
+ {
+ using RegistryKey? verKey = baseKey.OpenSubKey(subName);
+ string? javaHome = verKey?.GetValue("JavaHome") as string
+ ?? verKey?.GetValue("Path") as string;
+ string? resolved = ResolveJavaFromHomeDir(javaHome, checkedPaths, $"registry:{subName}");
+ if (resolved is not null)
+ {
+ return resolved;
+ }
+ }
+ }
+ catch
+ {
+ NoteChecked(checkedPaths, $"registry-error:HKLM\\{keyPath}");
+ }
+ }
+
+ return null;
+ }
+
+ private static string? FindJavaViaWhereExe(List checkedPaths)
+ {
+ if (!OperatingSystem.IsWindows())
+ {
+ return null;
+ }
+
+ try
+ {
+ ProcessStartInfo psi = new()
+ {
+ FileName = "where.exe",
+ Arguments = "java",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ };
+
+ using Process process = new() { StartInfo = psi };
+ if (!process.Start())
+ {
+ NoteChecked(checkedPaths, "where.exe:start-failed");
+ return null;
+ }
+
+ string output = process.StandardOutput.ReadToEnd();
+ process.WaitForExit(3000);
+ foreach (string line in output.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
+ {
+ NoteChecked(checkedPaths, $"where:{line}");
+ if (File.Exists(line)
+ && Path.GetFileName(line).Equals(JavaExeName, StringComparison.OrdinalIgnoreCase))
+ {
+ return line;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ NoteChecked(checkedPaths, $"where.exe:error:{ex.GetType().Name}");
+ }
+
+ return null;
+ }
+
+ private static string? FindJavaInCommonInstallLocations(List checkedPaths)
{
string[] roots =
[
@@ -621,7 +1353,9 @@ public sealed class SonicMfApiExecutor
"Amazon Corretto",
"Zulu",
"BellSoft",
- "Semeru"
+ "Semeru",
+ "Progress",
+ "Aurea"
];
foreach (string root in roots.Where(r => !string.IsNullOrWhiteSpace(r)).Distinct(StringComparer.OrdinalIgnoreCase))
@@ -634,8 +1368,8 @@ public sealed class SonicMfApiExecutor
continue;
}
- // vendor\bin\java.exe
string direct = Path.Combine(vendorDir, "bin", JavaExeName);
+ NoteChecked(checkedPaths, direct);
if (File.Exists(direct))
{
return direct;
@@ -647,12 +1381,14 @@ public sealed class SonicMfApiExecutor
.OrderByDescending(d => d, StringComparer.OrdinalIgnoreCase))
{
string candidate = Path.Combine(sub, "bin", JavaExeName);
+ NoteChecked(checkedPaths, candidate);
if (File.Exists(candidate))
{
return candidate;
}
string nestedJre = Path.Combine(sub, "jre", "bin", JavaExeName);
+ NoteChecked(checkedPaths, nestedJre);
if (File.Exists(nestedJre))
{
return nestedJre;
@@ -669,13 +1405,27 @@ public sealed class SonicMfApiExecutor
return null;
}
+ private static void NoteChecked(List checkedPaths, string path)
+ {
+ if (checkedPaths.Count >= MaxCheckedPathsInError * 2)
+ {
+ return;
+ }
+
+ if (!checkedPaths.Contains(path, StringComparer.OrdinalIgnoreCase))
+ {
+ checkedPaths.Add(path);
+ }
+ }
+
private static string JavaExeName => OperatingSystem.IsWindows() ? "java.exe" : "java";
- private static string? FindOnPath(string fileName)
+ private static string? FindOnPath(string fileName, List checkedPaths)
{
string? pathEnv = Environment.GetEnvironmentVariable("PATH");
if (string.IsNullOrWhiteSpace(pathEnv))
{
+ NoteChecked(checkedPaths, "PATH=(leer)");
return null;
}
@@ -684,6 +1434,7 @@ public sealed class SonicMfApiExecutor
try
{
string candidate = Path.Combine(dir.Trim().Trim('"'), fileName);
+ NoteChecked(checkedPaths, $"PATH:{candidate}");
if (File.Exists(candidate))
{
return candidate;
diff --git a/ZA.CoreService.ESBCertificateManager/appsettings.json b/ZA.CoreService.ESBCertificateManager/appsettings.json
index c108d53..0e5a457 100644
--- a/ZA.CoreService.ESBCertificateManager/appsettings.json
+++ b/ZA.CoreService.ESBCertificateManager/appsettings.json
@@ -14,8 +14,9 @@
"Username": "Administrator",
"Password": "Administrator",
// Standard: Sonic MF Management API (IAgentProxy.restart) – kein WinRM.
- // Benötigt JRE + Client-JARs unter SonicHome\\lib (oder MfClientLibPath).
- // Java: oft unter SonicHome\\jre – sonst JavaHome/JavaPath setzen (kein systemweites JAVA_HOME nötig).
+ // Benötigt JRE + Client-JARs unter SonicHome\\lib (oder MfClientLibPath / MQ_HOME).
+ // Java-Suche: JavaPath/JavaHome, JAVA_HOME/JRE_HOME, setenv.bat, rekursiv unter SonicHome
+ // (nicht nur SonicHome\\jre\\bin\\java.exe), Registry, where.exe. Optional JavaHome/JavaPath setzen.
// Optional-Fallback: "WinRm" / "LocalCmd" (stopcontainer/startcontainer).
"ManagementMode": "MfApi",
"SonicHome": "C:\\Sonic\\MQ10.0",