diff --git a/ZA.CoreService.ESBCertificateManager/Form1.cs b/ZA.CoreService.ESBCertificateManager/Form1.cs
index c69bb80..0084b62 100644
--- a/ZA.CoreService.ESBCertificateManager/Form1.cs
+++ b/ZA.CoreService.ESBCertificateManager/Form1.cs
@@ -40,7 +40,6 @@ namespace ZA.CoreService.ESBCertificateManager
private TextBox txtCertificatePath = null!;
private DataGridView dgvTargets = null!;
private ComboBox cmbSonicConnection = null!;
- private Button btnLoadFromSonic = null!;
private Label lblSonicStatus = null!;
private Panel navProgressPanel = null!;
@@ -1302,14 +1301,12 @@ namespace ZA.CoreService.ESBCertificateManager
if (_loadedTargets.Count == 0)
{
SetStatus(
- "Keine KnownContainers in appsettings. SonicConnections[].KnownContainers setzen oder „Container laden“.",
+ "Keine KnownContainers in appsettings. SonicConnections[].KnownContainers setzen.",
isError: true);
}
else
{
- SetStatus(
- $"{_loadedTargets.Count} Container aus appsettings. Optional: „Container laden“ für Live-Liste.",
- isError: false);
+ SetStatus($"{_loadedTargets.Count} Container aus appsettings.", isError: false);
}
}
catch (Exception ex)
@@ -1408,10 +1405,6 @@ namespace ZA.CoreService.ESBCertificateManager
dgvTargets.Enabled = idle;
}
- if (btnLoadFromSonic is not null)
- {
- btnLoadFromSonic.Enabled = idle && _sonicDiscovery.HasConnections;
- }
}
private void SetStatus(string message, bool isError)
@@ -1555,24 +1548,16 @@ namespace ZA.CoreService.ESBCertificateManager
SetTargetRowStatus(targetResult.TargetId, targetResult.StatusText);
}
- string details = string.Join(
- Environment.NewLine + Environment.NewLine,
- runResult.TargetResults.Select(r =>
- $"{r.TargetName}: {r.StatusText}" +
- (string.IsNullOrWhiteSpace(r.Detail) ? string.Empty : Environment.NewLine + r.Detail)));
-
SetStatus(
runResult.OverallSuccess
? $"Neustart verifiziert ({runResult.TargetResults.Count} Ziel(e))."
: "Neustart fehlgeschlagen oder nicht verifiziert.",
isError: !runResult.OverallSuccess);
- MessageBox.Show(
- this,
- details,
- runResult.OverallSuccess ? "Neustart verifiziert" : "Neustart fehlgeschlagen",
- MessageBoxButtons.OK,
- runResult.OverallSuccess ? MessageBoxIcon.Information : MessageBoxIcon.Warning);
+ if (runResult.OverallSuccess)
+ {
+ UpdateToNextStep(4);
+ }
}
catch (OperationCanceledException)
{
@@ -1693,7 +1678,7 @@ namespace ZA.CoreService.ESBCertificateManager
}
// ---------------------------------------------------------------
- // Sonic Management Console – Container-Discovery
+ // Sonic – Status (KnownContainers aus appsettings)
// ---------------------------------------------------------------
private void BuildSonicDiscoveryRow(Panel card)
@@ -1723,19 +1708,13 @@ namespace ZA.CoreService.ESBCertificateManager
cmbSonicConnection.Items.Add(conn.Name);
}
- btnLoadFromSonic = CreateSecondaryButton("Container laden");
- btnLoadFromSonic.Location = new Point(392, 103);
- btnLoadFromSonic.Size = new Size(148, 28);
- btnLoadFromSonic.Enabled = _sonicDiscovery.HasConnections;
- btnLoadFromSonic.Click += async (_, _) => await LoadFromSonicAsync();
-
lblSonicStatus = new Label
{
ForeColor = MutedTextColor,
Font = new Font("Segoe UI", 8.5f),
AutoSize = true,
MaximumSize = new Size(720, 0),
- Location = new Point(552, 100)
+ Location = new Point(392, 108)
};
cmbSonicConnection.SelectedIndexChanged += (_, _) => RefreshSonicStatusLine();
@@ -1751,11 +1730,10 @@ namespace ZA.CoreService.ESBCertificateManager
card.Controls.Add(sonicLabel);
card.Controls.Add(cmbSonicConnection);
- card.Controls.Add(btnLoadFromSonic);
card.Controls.Add(lblSonicStatus);
}
- private void RefreshSonicStatusLine(string? suffix = null)
+ private void RefreshSonicStatusLine()
{
if (!_sonicDiscovery.HasConnections)
{
@@ -1769,134 +1747,13 @@ namespace ZA.CoreService.ESBCertificateManager
.FirstOrDefault(c => string.Equals(c.Name, selectedName, StringComparison.OrdinalIgnoreCase))
?? _sonicDiscovery.Connections[0];
- string sonicHome = string.IsNullOrWhiteSpace(conn.SonicHome) ? "(leer)" : conn.SonicHome.Trim();
(string home, string? javaExe) = new SonicMfApiExecutor(conn).ResolveRuntimePaths();
string javaDisplay = string.IsNullOrWhiteSpace(javaExe)
- ? "java=? (unter SonicHome/JRE setzen)"
+ ? "java=? (JavaPath in appsettings setzen)"
: $"java={javaExe}";
- string baseText =
- $"{conn.ManagementModeDisplay} | SonicHome={home} | {javaDisplay}";
- if (!string.IsNullOrWhiteSpace(suffix))
- {
- baseText = $"{suffix} | {baseText}";
- }
-
- lblSonicStatus.Text = baseText;
+ lblSonicStatus.Text = $"{conn.ManagementModeDisplay} | SonicHome={home} | {javaDisplay}";
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;
-
- string? selectedConnection = cmbSonicConnection?.SelectedItem?.ToString();
- if (string.IsNullOrWhiteSpace(selectedConnection)) return;
-
- btnLoadFromSonic.Enabled = false;
- lblSonicStatus.Text = $"Verbinde mit {selectedConnection}…";
- lblSonicStatus.ForeColor = GoldColor;
-
- try
- {
- using CancellationTokenSource cts = new(TimeSpan.FromSeconds(30));
- SonicDiscoveryResult result = await _sonicDiscovery.DiscoverAsync(
- selectedConnection,
- _loadedTargets,
- cts.Token);
-
- if (!result.Success)
- {
- RefreshSonicStatusLine($"Fehler: {TruncateStatus(result.ErrorMessage)}");
- lblSonicStatus.ForeColor = RedColor;
- SetStatus($"Sonic-Discovery fehlgeschlagen: {result.ErrorMessage}", isError: true);
- return;
- }
-
- // Grid mit entdeckten + konfigurierten Containern befüllen
- _loadedTargets = result.DiscoveredTargets;
- BindTargetsToGrid(result.DiscoveredTargets);
-
- int total = result.DiscoveredTargets.Count;
- int remote = result.RawContainerNames.Count;
- string domain = string.IsNullOrWhiteSpace(result.DomainName)
- ? selectedConnection
- : result.DomainName;
-
- if (total == 0)
- {
- RefreshSonicStatusLine($"Verb. ok – 0 Container '{domain}'");
- lblSonicStatus.ForeColor = GoldColor;
- SetStatus(
- result.ErrorMessage
- ?? $"Sonic Domain '{domain}': keine Container. KnownContainers/SonicHome in appsettings prüfen.",
- isError: true);
- }
- else if (remote == 0)
- {
- RefreshSonicStatusLine($"Verb. ok – 0 remote, {total} Config '{domain}'");
- lblSonicStatus.ForeColor = GoldColor;
- SetStatus(
- $"Domain '{domain}': Remote leer – {total} Ziel(e) aus appsettings/KnownContainers. "
- + (result.ErrorMessage ?? string.Empty),
- isError: false);
- }
- else
- {
- RefreshSonicStatusLine($"Domain '{domain}': {remote} remote, {total} gesamt");
- SetStatus($"Sonic Domain '{domain}': {total} Ziel(e) geladen ({remote} remote).", isError: false);
- }
-
- MarkUnconfiguredRows();
- }
- catch (OperationCanceledException)
- {
- RefreshSonicStatusLine("Timeout");
- lblSonicStatus.ForeColor = RedColor;
- SetStatus($"Sonic-Discovery Timeout ({selectedConnection})", isError: true);
- }
- catch (Exception ex)
- {
- RefreshSonicStatusLine($"Fehler: {TruncateStatus(ex.Message)}");
- lblSonicStatus.ForeColor = RedColor;
- SetStatus($"Sonic-Discovery Fehler: {ex.Message}", isError: true);
- }
- finally
- {
- btnLoadFromSonic.Enabled = _sonicDiscovery.HasConnections && !_isOperationRunning;
- RefreshActionButtonStates();
- }
- }
-
- ///
- /// Färbt Zeilen mit unvollständiger Konfiguration (kein TargetDirectory) orange ein
- /// damit erkennbar ist, dass diese Container noch konfiguriert werden müssen.
- ///
- private void MarkUnconfiguredRows()
- {
- foreach (DataGridViewRow row in dgvTargets.Rows)
- {
- if (row.Tag is not DeploymentTarget target) continue;
-
- if (string.IsNullOrWhiteSpace(target.TargetDirectory))
- {
- row.DefaultCellStyle.ForeColor = GoldColor;
- if (row.Cells["Status"] is DataGridViewCell statusCell)
- {
- statusCell.Value = "⚠ Pfad fehlt";
- }
- }
- }
- }
}
}
diff --git a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
index 97622fe..0c7cba4 100644
--- a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
+++ b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
@@ -1,390 +1,39 @@
namespace ZA.CoreService.ESBCertificateManager.Models;
///
-/// Verbindungskonfiguration für eine Progress Sonic ESB Management Instanz.
-/// Name = Verbindungs-Alias (hier oft gleich ContainerName, z.B. "DE-Test").
-/// DomainName = Sonic-Domain (z.B. "proalpha-test").
-/// Container wird in KnownContainers / DeploymentTarget.ContainerName geführt (z.B. "DE-Test").
+/// Sonic-Verbindung für MfApi-Container-Restart (wie SMC).
///
public sealed class SonicConnection
{
- ///
- /// Alias der Verbindung; referenziert von .
- ///
+ /// Alias; referenziert von DeploymentTarget.SonicConnectionName.
public required string Name { get; init; }
- /// Sonic-Domain, z.B. "proalpha-test" (nicht der Containername).
+ /// Sonic-Domain, z.B. proalpha-test.
public required string DomainName { get; init; }
- ///
- /// Dieselbe Broker-/Management-URL wie in der Sonic Management Console (SMC),
- /// z.B. "tcp://dekun-painwbdet:13070". Keine separate Domain-Console nötig.
- ///
+ /// Broker-/Management-URL wie in der SMC, z.B. tcp://host:13070.
public required string ConnectionUrl { get; init; }
- /// Login wie in der Sonic Management Console (nicht für WinRM).
public required string Username { get; init; }
-
- /// Passwort wie in der Sonic Management Console (nicht für WinRM).
public required string Password { get; init; }
- ///
- /// Windows-Konto für WinRM (Invoke-Command -Credential).
- /// Leer = aktueller Prozess-Benutzer ohne explizite Credentials.
- /// Nicht mit / (Sonic SMC) verwechseln.
- ///
- public string WinRmUsername { get; init; } = string.Empty;
-
- /// Windows-Passwort für WinRM; nur relevant wenn gesetzt ist.
- public string WinRmPassword { get; init; } = string.Empty;
-
- ///
- /// MfApi = Sonic MF Management Runtime API über ConnectionUrl + SMC-Logins (Standard);
- /// WinRm / LocalCmd = optionaler Fallback über stopcontainer/startcontainer;
- /// HttpApi = REST (falls vorhanden).
- ///
- ///
- /// Standard: MfApi = Management Application API (wie SMC):
- /// JMSConnectorClient + MFProxyFactory.createAgentProxy + IAgentProxy.restart.
- /// Laut CX-Messenger-Doku-Index: Docs2017/api/mgmt_api (nicht stopcontainer.bat).
- /// LocalCmd nur wenn Server-Scripts existieren (bei reiner SMC oft nicht der Fall).
- ///
- public SonicManagementMode ManagementMode { get; init; } = SonicManagementMode.MfApi;
-
- ///
- /// Effektiver Modus: bei WinRm und lokalem ConnectionUrl-Host wird LocalCmd erzwungen.
- /// MfApi bleibt unverändert (nutzt Domain-Manager-Verbindung).
- ///
- public SonicManagementMode EffectiveManagementMode
- => ManagementMode == SonicManagementMode.WinRm && IsConnectionHostLocal(ConnectionUrl)
- ? SonicManagementMode.LocalCmd
- : ManagementMode;
-
- /// True wenn WinRm konfiguriert war, aber wegen lokalem Host auf LocalCmd umgestellt wurde.
- public bool IsLocalCmdAutoForced
- => ManagementMode == SonicManagementMode.WinRm
- && EffectiveManagementMode == SonicManagementMode.LocalCmd;
-
- /// Anzeigetext für UI.
- public string ManagementModeDisplay => "MfApi (SMC Management Application API)";
-
- ///
- /// True wenn der Host aus ConnectionUrl dieser Maschine entspricht
- /// (localhost / 127.0.0.1 / ::1 / Computername).
- ///
- public static bool IsConnectionHostLocal(string? connectionUrl)
- {
- if (string.IsNullOrWhiteSpace(connectionUrl))
- {
- return false;
- }
-
- string host;
- try
- {
- host = new Uri(connectionUrl).Host;
- }
- catch
- {
- host = connectionUrl.Trim();
- }
-
- if (string.IsNullOrWhiteSpace(host))
- {
- return false;
- }
-
- if (host.Equals("localhost", StringComparison.OrdinalIgnoreCase)
- || host.Equals("127.0.0.1", StringComparison.OrdinalIgnoreCase)
- || host.Equals("::1", StringComparison.OrdinalIgnoreCase)
- || host.Equals("[::1]", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- string machine = Environment.MachineName;
- if (host.Equals(machine, StringComparison.OrdinalIgnoreCase)
- || host.StartsWith(machine + ".", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- try
- {
- string dnsName = System.Net.Dns.GetHostName();
- if (!string.IsNullOrWhiteSpace(dnsName)
- && (host.Equals(dnsName, StringComparison.OrdinalIgnoreCase)
- || host.StartsWith(dnsName + ".", StringComparison.OrdinalIgnoreCase)))
- {
- return true;
- }
- }
- catch
- {
- // DNS optional
- }
-
- return false;
- }
-
- ///
- /// Sonic-/MQ-/ESB-Installationsroot, z.B. "C:\Sonic\MQ10.0" (Client-JARs oft unter lib).
- /// Bei ESB-Home: ggf. MfClientLibPath auf MQ\lib setzen.
- ///
+ /// Installationsroot (optional; Libs oft unter lib).
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/JRE_HOME, setenv.bat, rekursiv unter SonicHome, Registry, …).
- ///
+ /// Optional: JRE/JDK-Home.
public string JavaHome { get; init; } = string.Empty;
- ///
- /// Optionaler direkter Pfad zu java.exe (überschreibt JavaHome wenn gesetzt).
- ///
+ /// Optional: direkter Pfad zu java.exe.
public string JavaPath { get; init; } = string.Empty;
- ///
- /// Optionaler Pfad zu Sonic-Client-JARs für MfApi (mgmt_client.jar etc.).
- /// Leer = SonicHome\lib, MQ_HOME\lib, ESB_HOME\lib bzw. nested MQ*/lib.
- ///
+ /// Ordner mit mgmt_client.jar / mfcontext.jar / …
public string MfClientLibPath { get; init; } = string.Empty;
- ///
- /// Container-Namen (kurz), z.B. ["DE-Test"]. Nicht die Domain.
- ///
+ /// Container-Kurznamen, z.B. ct-ZADBService.
public List KnownContainers { get; init; } = [];
- public int ManagementHttpPort { get; init; } = 8080;
- public string ApiBasePath { get; init; } = "/api/v1";
- public string ContainerListPath { get; init; } = string.Empty;
- public string ContainerRestartPath { get; init; } = string.Empty;
- public string ContainerStopPath { get; init; } = string.Empty;
- public string ContainerStartPath { get; init; } = string.Empty;
-
- public int WinRmPort { get; init; } = 5985;
- public string WinRmRestartScript { get; init; } = string.Empty;
- public string WinRmContainerListScript { get; init; } = string.Empty;
- public string WinRmXapiImportScript { get; init; } = string.Empty;
-
public int TimeoutSeconds { get; init; } = 120;
public int PostRestartDelaySeconds { get; init; } = 20;
- public string ResolveRestartScript()
- => string.IsNullOrWhiteSpace(WinRmRestartScript)
- ? DefaultRestartScript
- : WinRmRestartScript;
-
- public string ResolveContainerListScript()
- => string.IsNullOrWhiteSpace(WinRmContainerListScript)
- ? DefaultContainerListScript
- : WinRmContainerListScript;
-
- ///
- /// Offizieller MF-Container-Neustart laut Aurea CX Messenger Doku:
- /// SonicHome\bin\stopcontainer.bat Domain.Container
- /// SonicHome\bin\startcontainer.bat Domain.Container
- /// Danach Prozess-Verifikation (alte PIDs weg, neue PIDs da).
- ///
- public const string DefaultRestartScript =
- """
- $ErrorActionPreference = 'Stop'
- $sonicHome = '{sonicHome}'
- $domain = '{domain}'
- $container = '{container}'
-
- $bin = Join-Path $sonicHome 'bin'
- $stopBat = Join-Path $bin 'stopcontainer.bat'
- $startBat = Join-Path $bin 'startcontainer.bat'
-
- # Kurzname = Container (z.B. DE-Test), Full = Domain.Container (z.B. proalpha-test.DE-Test)
- $shortName = if ($container -like '*.*') { ($container -split '\.', 2)[1] } else { $container }
- $fullName = if ($container -like '*.*') { $container } else { "$domain.$container" }
- $markers = @($shortName, $fullName, "$domain.$shortName") | Select-Object -Unique
-
- function Get-ContainerPids {
- $pids = @()
- Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
- Where-Object {
- $cmd = $_.CommandLine
- if (-not $cmd) { return $false }
- if ($_.Name -notmatch 'java|javaw|sonic') { return $false }
- foreach ($m in $markers) {
- if ($cmd -like "*$m*") { return $true }
- }
- return $false
- } |
- ForEach-Object { $pids += [int]$_.ProcessId }
- return @($pids | Select-Object -Unique)
- }
-
- function Wait-PidsGone([int[]]$pids, [int]$seconds) {
- $deadline = (Get-Date).AddSeconds($seconds)
- while ((Get-Date) -lt $deadline) {
- $alive = @($pids | Where-Object { Get-Process -Id $_ -ErrorAction SilentlyContinue })
- if ($alive.Count -eq 0) { return $true }
- Start-Sleep -Seconds 2
- }
- return $false
- }
-
- function Wait-NewPids([int[]]$oldPids, [int]$seconds) {
- $deadline = (Get-Date).AddSeconds($seconds)
- while ((Get-Date) -lt $deadline) {
- $now = @(Get-ContainerPids)
- $fresh = @($now | Where-Object { $oldPids -notcontains $_ })
- if ($fresh.Count -gt 0) { return ,$fresh }
- Start-Sleep -Seconds 2
- }
- return ,@()
- }
-
- function Invoke-ContainerBat([string]$bat, [string]$name) {
- if (-not (Test-Path -LiteralPath $bat)) {
- throw "Sonic BAT fehlt: $bat (SonicHome pruefen)"
- }
- $arg = '/c "' + $bat + '" "' + $name + '"'
- $p = Start-Process -FilePath 'cmd.exe' -ArgumentList $arg -Wait -PassThru -NoNewWindow
- return [int]$p.ExitCode
- }
-
- Write-Output "INFO:Domain=$domain Container=$shortName Full=$fullName"
- Write-Output "INFO:RestartVia=stopcontainer/startcontainer (MF Container)"
- $before = @(Get-ContainerPids)
- Write-Output "INFO:PIDsBefore=$($before -join ',')"
-
- if ($before.Count -eq 0) {
- Write-Output "WARN:No running Java/Sonic process for '$shortName' - starting anyway"
- }
-
- # 1) Offiziell: stopcontainer.bat Domain.Container (danach Kurzname als Fallback)
- $stopOk = $false
- foreach ($n in @($fullName, $shortName)) {
- Write-Output "INFO:stopcontainer $n"
- $code = Invoke-ContainerBat -bat $stopBat -name $n
- Write-Output "INFO:stopcontainer ExitCode=$code Name=$n"
- if ($code -eq 0) { $stopOk = $true; break }
- }
- if (-not $stopOk) {
- Write-Output "WARN:stopcontainer non-zero; will force-stop remaining PIDs if any"
- }
-
- Start-Sleep -Seconds 3
- $still = @(Get-ContainerPids)
-
- # 2) Force-Stop falls BAT den Prozess nicht beendet (sonst kein echter Restart in SMC)
- if ($still.Count -gt 0) {
- Write-Output "INFO:Force-Stop PIDs=$($still -join ',')"
- foreach ($procId in $still) {
- Stop-Process -Id $procId -Force -ErrorAction SilentlyContinue
- }
- }
-
- if ($before.Count -gt 0) {
- if (-not (Wait-PidsGone -pids $before -seconds 45)) {
- throw "Container process still running after stop (PIDs=$($before -join ','))"
- }
- Write-Output "INFO:Old PIDs gone"
- }
-
- Start-Sleep -Seconds 3
-
- # 3) Offiziell: startcontainer.bat Domain.Container
- $started = $false
- foreach ($n in @($fullName, $shortName)) {
- Write-Output "INFO:startcontainer $n"
- $code = Invoke-ContainerBat -bat $startBat -name $n
- Write-Output "INFO:startcontainer ExitCode=$code Name=$n"
- if ($code -eq 0) { $started = $true; break }
- }
-
- if (-not $started) {
- throw "startcontainer failed for $fullName / $shortName"
- }
-
- $after = @(Wait-NewPids -oldPids $before -seconds 60)
- if ($after.Count -eq 0) {
- $any = @(Get-ContainerPids)
- if ($any.Count -eq 0) {
- throw "After start no process for container '$shortName'. Check SMC / SonicHome / ContainerName."
- }
- Write-Output "INFO:PIDsAfter=$($any -join ',')"
- }
- else {
- Write-Output "INFO:PIDsAfter=$($after -join ',')"
- }
-
- Write-Output "OK:ContainerRestartVerified Domain=$domain Container=$shortName"
- """;
-
- public const string DefaultContainerListScript =
- """
- $ErrorActionPreference = 'Continue'
- $sonicHome = '{sonicHome}'
- $domain = '{domain}'
- $names = New-Object System.Collections.Generic.List[string]
-
- function Add-Name([string]$n) {
- if ([string]::IsNullOrWhiteSpace($n)) { return }
- $n = $n.Trim()
- if (-not $names.Contains($n)) { [void]$names.Add($n) }
- }
-
- if (-not (Test-Path -LiteralPath $sonicHome)) {
- Write-Output "WARN:SonicHomeNichtGefunden:$sonicHome"
- }
- else {
- Write-Output "INFO:SonicHomeOk:$sonicHome Domain=$domain"
-
- Get-ChildItem -LiteralPath $sonicHome -Directory -ErrorAction SilentlyContinue |
- ForEach-Object {
- if ($_.Name -like '*.cache') {
- Add-Name ($_.Name -replace '\.cache$', '')
- }
- Get-ChildItem -LiteralPath $_.FullName -Directory -ErrorAction SilentlyContinue |
- Where-Object { $_.Name -like '*.cache' } |
- ForEach-Object { Add-Name ($_.Name -replace '\.cache$', '') }
- }
-
- Get-ChildItem -LiteralPath $sonicHome -Recurse -Filter 'container.xml' -File -ErrorAction SilentlyContinue |
- Select-Object -First 40 |
- ForEach-Object {
- Add-Name (Split-Path $_.DirectoryName -Leaf)
- }
- }
-
- Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
- Where-Object { $_.CommandLine -match 'sonic|mf\.framework|container\.xml' } |
- ForEach-Object {
- if ($_.CommandLine -match '([A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)\.cache') {
- Add-Name $Matches[1]
- }
- elseif ($_.CommandLine -match '\\([A-Za-z0-9_\-]+)\\container\.xml') {
- Add-Name $Matches[1]
- }
- }
-
- # Kurzform Domain.Container → Container
- foreach ($n in @($names.ToArray())) {
- if ($n -like '*.*') {
- $parts = $n -split '\.', 2
- if ($parts.Count -eq 2) { Add-Name $parts[1] }
- }
- }
-
- if ($names.Count -eq 0) {
- Write-Output "WARN:KeineContainerGefunden Domain=$domain SonicHome=$sonicHome"
- }
-
- $names | Sort-Object -Unique
- """;
-}
-
-public enum SonicManagementMode
-{
- HttpApi = 0,
- WinRm = 1,
- LocalCmd = 2,
- /// Sonic MF Management API über Domain-Manager (ConnectionUrl + SMC-Credentials).
- MfApi = 3
+ public string ManagementModeDisplay => "MfApi (SMC Restart)";
}
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicContainerDiscovery.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicContainerDiscovery.cs
index 739a156..e41ef1c 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicContainerDiscovery.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicContainerDiscovery.cs
@@ -3,8 +3,7 @@ using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
///
-/// Fragt konfigurierte Sonic-Verbindungen nach Containern ab
-/// und merged Remote-Treffer mit KnownContainers / Sample-Zielen.
+/// Liefert Ziele nur aus appsettings KnownContainers (kein Live-Ping/List).
///
public sealed class SonicContainerDiscovery
{
@@ -18,9 +17,6 @@ public sealed class SonicContainerDiscovery
public bool HasConnections => _connections.Count > 0;
public IReadOnlyList Connections => _connections;
- ///
- /// Ziele nur aus appsettings KnownContainers (kein Offline-JSON).
- ///
public IReadOnlyList BuildTargetsFromConfig()
{
List result = [];
@@ -49,252 +45,4 @@ public sealed class SonicContainerDiscovery
return result;
}
-
- public async Task DiscoverAsync(
- string connectionName,
- IReadOnlyList knownTargets,
- CancellationToken cancellationToken = default)
- {
- SonicConnection? connection = _connections
- .FirstOrDefault(c => string.Equals(c.Name, connectionName, StringComparison.OrdinalIgnoreCase));
-
- if (connection is null)
- {
- return SonicDiscoveryResult.Failed(connectionName,
- $"Sonic-Verbindung '{connectionName}' ist nicht in AppSettings konfiguriert.");
- }
-
- using SonicManagementClient client = new(connection);
-
- (bool reachable, string? pingError, string? resolvedPath) = await client.CheckConnectionAsync(cancellationToken);
-
- List diagnostics = [];
- List remoteContainers = [];
- bool listOk = false;
- string? listError = null;
-
- if (!reachable)
- {
- // Trotzdem KnownContainers nutzen – Neustart kann über SonicBin (stop/startcontainer) gehen.
- diagnostics.Add($"Management-Ping: {pingError}");
- if (connection.KnownContainers.Count == 0
- && !knownTargets.Any(t =>
- string.Equals(t.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase)
- && !string.IsNullOrWhiteSpace(t.ContainerName)))
- {
- return SonicDiscoveryResult.Failed(connectionName,
- $"Management-Konsole nicht erreichbar: {pingError}");
- }
- }
- else
- {
- (listOk, IReadOnlyList remoteNames, listError) =
- await client.GetContainersAsync(cancellationToken);
-
- foreach (string line in remoteNames)
- {
- if (line.StartsWith("WARN:", StringComparison.OrdinalIgnoreCase)
- || line.StartsWith("INFO:", StringComparison.OrdinalIgnoreCase))
- {
- diagnostics.Add(line);
- continue;
- }
-
- remoteContainers.Add(line);
- }
-
- if (!listOk)
- {
- diagnostics.Add($"Listen-Fehler: {listError}");
- remoteContainers = [];
- }
- }
-
- // Fallback: explizit in appsettings hinterlegte Container
- List mergedNames = MergeContainerNames(
- remoteContainers,
- connection.KnownContainers,
- knownTargets
- .Where(t => string.Equals(t.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase))
- .Select(t => t.ContainerName)
- .Where(n => !string.IsNullOrWhiteSpace(n)));
-
- List discovered = BuildTargets(connection, mergedNames, knownTargets);
-
- string? hint = BuildHint(connection, remoteContainers.Count, connection.KnownContainers.Count, diagnostics, listOk, listError);
-
- return new SonicDiscoveryResult
- {
- ConnectionName = connectionName,
- DomainName = connection.DomainName,
- Success = true,
- ErrorMessage = hint,
- DiscoveredTargets = discovered,
- RawContainerNames = remoteContainers,
- ResolvedPath = resolvedPath
- };
- }
-
- private static List MergeContainerNames(
- IEnumerable remote,
- IEnumerable knownConfigured,
- IEnumerable knownFromTargets)
- {
- List result = [];
-
- foreach (string name in remote.Concat(knownConfigured).Concat(knownFromTargets))
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- continue;
- }
-
- if (!result.Any(existing => ContainerNamesMatch(existing, name, domain: null)))
- {
- result.Add(name.Trim());
- }
- }
-
- return result;
- }
-
- private static string? BuildHint(
- SonicConnection connection,
- int remoteCount,
- int knownConfigCount,
- List diagnostics,
- bool listOk,
- string? listError)
- {
- List parts = [];
-
- if (!listOk && !string.IsNullOrWhiteSpace(listError))
- {
- parts.Add(listError!);
- }
-
- if (remoteCount == 0)
- {
- parts.Add(
- $"Remote hat 0 Container geliefert (Domain '{connection.DomainName}', SonicHome='{connection.SonicHome}').");
-
- if (knownConfigCount > 0)
- {
- parts.Add($"Fallback: {knownConfigCount} KnownContainers aus appsettings.");
- }
- else
- {
- parts.Add("Tipp: KnownContainers in appsettings setzen oder SonicHome korrigieren.");
- }
- }
-
- foreach (string d in diagnostics.Take(3))
- {
- parts.Add(d);
- }
-
- return parts.Count == 0 ? null : string.Join(" ", parts);
- }
-
- private static List BuildTargets(
- SonicConnection connection,
- IReadOnlyList containerNames,
- IReadOnlyList knownTargets)
- {
- List result = [];
- int syntheticId = -1;
-
- foreach (string containerName in containerNames)
- {
- DeploymentTarget? existing = knownTargets.FirstOrDefault(t =>
- string.Equals(t.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase)
- && ContainerNamesMatch(t.ContainerName, containerName, connection.DomainName));
-
- if (existing is not null)
- {
- if (!result.Any(r => r.Id == existing.Id))
- {
- result.Add(existing);
- }
- }
- else
- {
- result.Add(new DeploymentTarget
- {
- Id = syntheticId--,
- Name = $"{connection.Name} / {containerName}",
- Environment = connection.DomainName,
- IsActive = true,
- TargetDirectory = string.Empty,
- CertificateFileName = string.Empty,
- ContainerName = containerName,
- RestartType = RestartType.SonicContainer,
- SonicConnectionName = connection.Name,
- SortOrder = result.Count * 10
- });
- }
- }
-
- foreach (DeploymentTarget known in knownTargets)
- {
- if (!string.Equals(known.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- bool alreadyAdded = result.Any(r =>
- ContainerNamesMatch(r.ContainerName, known.ContainerName, connection.DomainName)
- || r.Id == known.Id);
-
- if (!alreadyAdded)
- {
- result.Add(known);
- }
- }
-
- return result;
- }
-
- internal static bool ContainerNamesMatch(string? a, string? b, string? domain)
- {
- if (string.IsNullOrWhiteSpace(a) || string.IsNullOrWhiteSpace(b))
- {
- return false;
- }
-
- if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- string aShort = StripDomainPrefix(a, domain);
- string bShort = StripDomainPrefix(b, domain);
- return string.Equals(aShort, bShort, StringComparison.OrdinalIgnoreCase);
- }
-
- private static string StripDomainPrefix(string name, string? domain)
- {
- if (!string.IsNullOrWhiteSpace(domain)
- && name.StartsWith(domain + ".", StringComparison.OrdinalIgnoreCase))
- {
- return name[(domain.Length + 1)..];
- }
-
- int dot = name.IndexOf('.');
- return dot > 0 ? name[(dot + 1)..] : name;
- }
-}
-
-public sealed class SonicDiscoveryResult
-{
- public required string ConnectionName { get; init; }
- public string DomainName { get; init; } = string.Empty;
- public bool Success { get; init; }
- public string? ErrorMessage { get; init; }
- public string? ResolvedPath { get; init; }
- public IReadOnlyList DiscoveredTargets { get; init; } = [];
- public IReadOnlyList RawContainerNames { get; init; } = [];
-
- public static SonicDiscoveryResult Failed(string connectionName, string error)
- => new() { ConnectionName = connectionName, Success = false, ErrorMessage = error };
}
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
index 56bb6c3..9552a80 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
@@ -3,7 +3,7 @@ using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
///
-/// Sonic MfApi (wie SMC-Neustart) – ohne WinRM/HTTP/XApi.
+/// Schlanke Fassade: nur Container-Neustart über MfApi.
///
public sealed class SonicManagementClient : IDisposable
{
@@ -16,45 +16,6 @@ public sealed class SonicManagementClient : IDisposable
_mfApi = new SonicMfApiExecutor(connection);
}
- public async Task<(bool Success, string? Error, string? ResolvedPath)> CheckConnectionAsync(
- CancellationToken cancellationToken = default)
- {
- (bool ok, string? error) = await _mfApi.TestConnectionAsync(cancellationToken);
- if (ok)
- {
- return (true, null, $"MfApi {_connection.ConnectionUrl} Domain={_connection.DomainName}");
- }
-
- if (_connection.KnownContainers.Count > 0
- && await IsTcpReachableAsync(_connection.ConnectionUrl, cancellationToken))
- {
- return (true, null,
- $"MfApi-Ping fehlgeschlagen, KnownContainers/TCP ok. Hinweis: {Truncate(error)}");
- }
-
- return (false, error ?? "MfApi-Verbindung fehlgeschlagen", null);
- }
-
- public async Task<(bool Success, IReadOnlyList ContainerNames, string? Error)> GetContainersAsync(
- CancellationToken cancellationToken = default)
- {
- (bool ok, IReadOnlyList names, string? error) =
- await _mfApi.ListContainersAsync(cancellationToken);
-
- if (ok && names.Count > 0)
- {
- return (true, names, null);
- }
-
- if (_connection.KnownContainers.Count > 0)
- {
- return (true, _connection.KnownContainers,
- ok ? null : $"Liste leer/fehlerhaft – KnownContainers. {error}");
- }
-
- return (false, [], error ?? "Keine Container gefunden.");
- }
-
public async Task<(bool Success, string Status, string? Detail)> RestartContainerAsync(
string containerName,
CancellationToken cancellationToken = default)
@@ -77,27 +38,6 @@ public sealed class SonicManagementClient : IDisposable
$"Fehler: {error}\n\n{output}");
}
- private static async Task IsTcpReachableAsync(string connectionUrl, CancellationToken cancellationToken)
- {
- try
- {
- Uri uri = new(connectionUrl);
- using System.Net.Sockets.TcpClient tcp = new();
- using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- cts.CancelAfter(TimeSpan.FromSeconds(5));
- await tcp.ConnectAsync(uri.Host, uri.Port > 0 ? uri.Port : 2506, cts.Token);
- return true;
- }
- catch
- {
- return false;
- }
- }
-
- private static string Truncate(string? s, int max = 180)
- => string.IsNullOrWhiteSpace(s) ? string.Empty
- : s.Length <= max ? s : s[..max] + "…";
-
public void Dispose()
{
}
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
index 034f21c..f495fd9 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs
@@ -1,23 +1,14 @@
using System.Diagnostics;
using System.Text;
-using System.Text.RegularExpressions;
-using Microsoft.Win32;
using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
///
-/// Führt Sonic-Container-Operationen über die offizielle MF Management Runtime API aus
-/// (JMSConnectorClient + MFProxyFactory + IAgentProxy.restart), per Java-Hilfsprogramm
-/// und Client-JARs unter SonicHome/lib bzw. MfClientLibPath.
-/// Nutzt ConnectionUrl + Username/Password aus appsettings (SMC / Domain Manager).
+/// Startet nur den Container-Restart über SonicMfContainerTool (Java + MF-Client-JARs).
///
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)
@@ -25,88 +16,25 @@ 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);
-
- public async Task<(bool Success, IReadOnlyList Containers, string? Error)> ListContainersAsync(
- CancellationToken cancellationToken = default)
- {
- (bool ok, string? output, string? error) = await RunRawAsync("list", null, cancellationToken);
- if (!ok)
- {
- return (false, [], error ?? output);
- }
-
- List names = (output ?? string.Empty)
- .Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- .Where(l => !l.StartsWith("OK:", StringComparison.OrdinalIgnoreCase))
- .Where(l => !l.StartsWith("INFO:", StringComparison.OrdinalIgnoreCase))
- .Where(l => !l.StartsWith("ERROR:", StringComparison.OrdinalIgnoreCase))
- .Where(l => !l.StartsWith("WARN:", StringComparison.OrdinalIgnoreCase))
- .Where(l => !l.StartsWith("Usage:", StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- return (true, names, null);
+ return (sonicHome, ResolveJavaExe());
}
public async Task<(bool Success, string? Output, string? Error)> RestartAsync(
string containerName,
CancellationToken cancellationToken = default)
- {
- (bool ok, string? output, string? error) = await RunRawAsync("restart", containerName, cancellationToken);
- if (!ok)
- {
- return (false, output, error);
- }
-
- bool invoked = (output ?? string.Empty)
- .Contains("OK:RestartInvoked", StringComparison.OrdinalIgnoreCase);
- return invoked
- ? (true, output, error)
- : (false, output, error ?? "Kein OK:RestartInvoked von SonicMfContainerTool.");
- }
-
- private async Task<(bool Success, string? Error)> RunAsync(
- string command,
- string? container,
- CancellationToken cancellationToken)
- {
- (bool ok, string? output, string? error) = await RunRawAsync(command, container, cancellationToken);
- if (ok)
- {
- return (true, null);
- }
-
- return (false, error ?? output);
- }
-
- private async Task<(bool Success, string? Output, string? Error)> RunRawAsync(
- string command,
- string? container,
- CancellationToken cancellationToken)
{
(bool prepared, string? javaExe, string? classDir, string? classpath, string? prepareError) =
- await PrepareToolAsync(cancellationToken);
+ PrepareTool();
if (!prepared)
{
return (false, null, prepareError);
}
- // ArgumentList statt manueller Quotes: sonst landet \"...\" im Classpath
- // und Java findet JMSConnectorAddress trotz vorhandener JARs nicht.
ProcessStartInfo psi = new()
{
FileName = javaExe!,
@@ -122,22 +50,18 @@ public sealed class SonicMfApiExecutor
psi.ArgumentList.Add("-cp");
psi.ArgumentList.Add(classpath!);
psi.ArgumentList.Add("SonicMfContainerTool");
- psi.ArgumentList.Add(command);
+ psi.ArgumentList.Add("restart");
psi.ArgumentList.Add("--domain");
psi.ArgumentList.Add(_connection.DomainName);
psi.ArgumentList.Add("--url");
psi.ArgumentList.Add(_connection.ConnectionUrl);
psi.ArgumentList.Add("--user");
psi.ArgumentList.Add(_connection.Username);
+ psi.ArgumentList.Add("--container");
+ psi.ArgumentList.Add(containerName);
psi.ArgumentList.Add("--timeout");
psi.ArgumentList.Add(Math.Clamp(_connection.TimeoutSeconds, 5, 600).ToString());
- if (!string.IsNullOrWhiteSpace(container))
- {
- psi.ArgumentList.Add("--container");
- psi.ArgumentList.Add(container);
- }
-
psi.Environment["ESB_SONIC_PASSWORD"] = _connection.Password ?? string.Empty;
using Process process = new() { StartInfo = psi };
@@ -167,8 +91,11 @@ public sealed class SonicMfApiExecutor
string stderr = (await stderrTask).Trim();
string combined = string.Join("\n", new[] { stdout, stderr }.Where(s => s.Length > 0));
- if (process.ExitCode == 0
- && !combined.Contains("ERROR:", StringComparison.OrdinalIgnoreCase))
+ bool ok = process.ExitCode == 0
+ && combined.Contains("OK:RestartInvoked", StringComparison.OrdinalIgnoreCase)
+ && !combined.Contains("ERROR:", StringComparison.OrdinalIgnoreCase);
+
+ if (ok)
{
return (true, combined, null);
}
@@ -180,1737 +107,157 @@ public sealed class SonicMfApiExecutor
|| combined.Contains("JMSConnectorAddress", StringComparison.OrdinalIgnoreCase))
{
err +=
- "\n\nClasspath unvollständig: com.sonicsw.mf.jmx.client.JMSConnectorAddress fehlt.\n" +
- "Bitte in appsettings MfClientLibPath auf den Ordner mit mgmt_client.jar / mfcontext.jar / sonic_Client.jar setzen\n" +
- $"(aktuell SonicHome='{_connection.SonicHome}').\n" +
- "Hinweis: Container-Kurzname laut SMC ist 'ct-ZADBService' (nicht der Verbindungs-Alias DE-Test).";
+ "\n\nClasspath unvollständig. MfClientLibPath auf Ordner mit mgmt_client.jar / mfcontext.jar setzen.";
}
- if (!combined.Contains("ToolVersion=", StringComparison.OrdinalIgnoreCase))
- {
- err +=
- "\n\nWARN: Ausgabe enthält kein INFO:ToolVersion=… – vermutlich alte SonicMfContainerTool.class.\n" +
- "App neu bauen (Debug+Release), Tools-Ordner im Output prüfen, Temp esb-sonic-mf* löschen.";
- }
-
- // Volle Ausgabe mitliefern (INFO/WARN), nicht nur die ERROR-Zeile
string detail = string.IsNullOrWhiteSpace(combined) ? err : err + "\n\n--- Tool-Output ---\n" + combined;
return (false, combined.Length > 0 ? combined : null, detail);
}
- private static void TryDeleteTempToolCache()
+ private (bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error) PrepareTool()
{
- try
- {
- string dir = Path.Combine(Path.GetTempPath(), "esb-sonic-mf-j8");
- if (Directory.Exists(dir))
- {
- Directory.Delete(dir, recursive: true);
- }
- }
- catch
- {
- /* ignore */
- }
- }
-
- private async Task<(bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error)>
- PrepareToolAsync(CancellationToken cancellationToken)
- {
- // Tool-Bytecode ist Java 8 (major 52). Sonic-mitgelieferte JREs sind oft Java 6/7 → unbrauchbar.
- // Deshalb: Runtime mit major>=52 bevorzugen (PATH/JAVA_HOME/Registry), Libs weiter aus SonicHome.
- const int minClassMajor = 52;
-
- JavaDiscoveryResult javaResult = DiscoverJava();
- string? javaExe = javaResult.JavaExe;
- int runtimeMajor = javaExe is null
- ? 0
- : await GetJavaClassMajorAsync(javaExe, cancellationToken);
-
- if (javaExe is null || runtimeMajor < minClassMajor)
- {
- (string? newerJava, int newerMajor, List probed) =
- await FindJavaWithMinimumMajorAsync(minClassMajor, cancellationToken);
- if (newerJava is not null)
- {
- javaExe = newerJava;
- runtimeMajor = newerMajor;
- javaResult.CheckedPaths.Add($"UPGRADE:RuntimeJava8+={newerJava} major={newerMajor}");
- }
- }
-
+ string? javaExe = ResolveJavaExe();
if (javaExe is null)
{
- 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));
-
return (false, null, null, null,
- "Java nicht gefunden.\n" +
- $"Verwendetes SonicHome: '{sonicHome}'\n" +
- "Konfiguration: JavaPath/JavaHome auf eine Java-8+-Runtime setzen.\n" +
- "Geprüfte Pfade:\n - " + checkedList);
+ "Java nicht gefunden. In appsettings JavaPath auf java.exe (Java 8+) setzen.");
}
- if (runtimeMajor < minClassMajor)
- {
- return (false, null, null, null,
- "Gefundene Java-Runtime ist zu alt für SonicMfContainerTool (braucht Java 8 / major 52).\n" +
- $"Aktuell: {javaExe} (class major={runtimeMajor}).\n" +
- "Die JRE unter SonicHome ist oft Java 6/7 – bitte Java 8+ installieren und in appsettings setzen:\n" +
- " \"JavaPath\": \"C:\\\\Program Files\\\\Java\\\\jre1.8.0_xxx\\\\bin\\\\java.exe\"\n" +
- "Sonic-Client-JARs bleiben unter SonicHome\\lib.");
- }
-
- (string? libClasspath, string? libError) = ResolveSonicClasspathDetailed();
+ (string? libClasspath, string? libError) = ResolveSonicClasspath();
if (libClasspath is null)
{
return (false, null, null, null, libError);
}
- // Vorcompilierte .class nur nutzen, wenn Class-Version passt.
- // Tool-Verzeichnis ZUERST im Classpath, damit keine alte Klasse aus Temp/JAR gewinnt.
- if (TryResolvePrebuiltTool(runtimeMajor, out string? prebuiltDir, out string? prebuiltEntry, out string? prebuiltError)
- && prebuiltDir is not null && prebuiltEntry is not null)
- {
- // Veraltete Temp-Kopien entfernen (früheres Compile-Cache).
- TryDeleteTempToolCache();
- string classpath = prebuiltEntry + Path.PathSeparator + libClasspath;
- return (true, javaExe, prebuiltDir, classpath, null);
- }
-
- // Zur Laufzeit aus .java für Java 8 kompilieren (--release 8 / -source 1.8 -target 1.8).
- string? sourcePath = ResolveToolSourcePath();
- if (sourcePath is null)
+ string? toolsDir = ResolveToolsDir();
+ if (toolsDir is null)
{
return (false, null, null, null,
- (prebuiltError ?? "Kein SonicMfContainerTool gefunden.") +
- " Tools\\SonicMfContainerTool.java/.class fehlen.\n" +
- $"Runtime-Java: {javaExe} (class major max={runtimeMajor}).");
+ "Tools\\SonicMfContainerTool.class nicht gefunden. Projekt neu bauen.");
}
- TryDeleteTempToolCache();
- string workDir = Path.Combine(Path.GetTempPath(), "esb-sonic-mf-j8");
- Directory.CreateDirectory(workDir);
-
- string javaTarget = Path.Combine(workDir, "SonicMfContainerTool.java");
- string classFile = Path.Combine(workDir, "SonicMfContainerTool.class");
-
- File.Copy(sourcePath, javaTarget, overwrite: true);
-
- string compileClasspath = libClasspath;
- // workDir zuerst
- string runtimeClasspath = workDir + Path.PathSeparator + libClasspath;
-
- bool classOk = File.Exists(classFile)
- && ReadClassFileMajorVersion(classFile) is int existingMajor
- && existingMajor <= runtimeMajor
- && File.GetLastWriteTimeUtc(classFile) >= File.GetLastWriteTimeUtc(sourcePath);
-
- if (!classOk)
- {
- string? javac = ResolveJavacExecutable(javaExe);
- if (javac is null)
- {
- return (false, null, null, null,
- "SonicMfContainerTool muss für Java 8 gebaut werden, aber javac fehlt.\n" +
- "Tools\\SonicMfContainerTool.class (major<=52) mit ausliefern oder JDK installieren.\n" +
- $"Gefundene java.exe: {javaExe}");
- }
-
- // Wichtig: ohne --release 8 erzeugt modernes javac major 65 → UnsupportedClassVersionError auf Sonic-JRE 8.
- string releaseArgs = SupportsJavacRelease8(javac)
- ? "--release 8"
- : "-source 1.8 -target 1.8";
-
- ProcessStartInfo compilePsi = new()
- {
- FileName = javac,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true,
- StandardOutputEncoding = Encoding.UTF8,
- StandardErrorEncoding = Encoding.UTF8
- };
-
- if (releaseArgs.StartsWith("--release", StringComparison.Ordinal))
- {
- compilePsi.ArgumentList.Add("--release");
- compilePsi.ArgumentList.Add("8");
- }
- else
- {
- compilePsi.ArgumentList.Add("-source");
- compilePsi.ArgumentList.Add("1.8");
- compilePsi.ArgumentList.Add("-target");
- compilePsi.ArgumentList.Add("1.8");
- }
-
- compilePsi.ArgumentList.Add("-encoding");
- compilePsi.ArgumentList.Add("UTF-8");
- compilePsi.ArgumentList.Add("-cp");
- compilePsi.ArgumentList.Add(compileClasspath);
- compilePsi.ArgumentList.Add("-d");
- compilePsi.ArgumentList.Add(workDir);
- compilePsi.ArgumentList.Add(javaTarget);
-
- using Process compile = new() { StartInfo = compilePsi };
- if (!compile.Start())
- {
- return (false, null, null, null, "javac konnte nicht gestartet werden.");
- }
-
- string cOut = await compile.StandardOutput.ReadToEndAsync(cancellationToken);
- string cErr = await compile.StandardError.ReadToEndAsync(cancellationToken);
- await compile.WaitForExitAsync(cancellationToken);
-
- int? builtMajor = File.Exists(classFile) ? ReadClassFileMajorVersion(classFile) : null;
- if (compile.ExitCode != 0 || builtMajor is null || builtMajor > runtimeMajor)
- {
- return (false, null, null, null,
- "Kompilieren von SonicMfContainerTool für Java 8 fehlgeschlagen.\n" +
- Truncate((cErr + "\n" + cOut).Trim()) +
- $"\nErzeugt major={builtMajor?.ToString() ?? "?"}, Runtime erlaubt <={runtimeMajor}.\n" +
- $"Classpath: {Truncate(compileClasspath, 240)}");
- }
- }
-
- return (true, javaExe, workDir, runtimeClasspath, null);
+ string classpath = toolsDir + Path.PathSeparator + libClasspath;
+ return (true, javaExe, toolsDir, classpath, null);
}
- private bool TryResolvePrebuiltTool(
- int runtimeMajor,
- out string? workDir,
- out string? classpathEntry,
- out string? error)
+ private string? ResolveJavaExe()
{
- workDir = null;
- classpathEntry = null;
- error = null;
+ foreach (string? candidate in EnumerateJavaCandidates())
+ {
+ if (!string.IsNullOrWhiteSpace(candidate) && File.Exists(candidate))
+ {
+ return Path.GetFullPath(candidate);
+ }
+ }
- string[] searchDirs =
+ return null;
+ }
+
+ private IEnumerable EnumerateJavaCandidates()
+ {
+ if (!string.IsNullOrWhiteSpace(_connection.JavaPath))
+ {
+ yield return _connection.JavaPath.Trim();
+ }
+
+ if (!string.IsNullOrWhiteSpace(_connection.JavaHome))
+ {
+ yield return Path.Combine(_connection.JavaHome.Trim(), "bin", "java.exe");
+ }
+
+ string? javaHome = Environment.GetEnvironmentVariable("JAVA_HOME");
+ if (!string.IsNullOrWhiteSpace(javaHome))
+ {
+ yield return Path.Combine(javaHome.Trim(), "bin", "java.exe");
+ }
+
+ string? jreHome = Environment.GetEnvironmentVariable("JRE_HOME");
+ if (!string.IsNullOrWhiteSpace(jreHome))
+ {
+ yield return Path.Combine(jreHome.Trim(), "bin", "java.exe");
+ }
+
+ yield return "java.exe"; // PATH
+ }
+
+ private (string? Classpath, string? Error) ResolveSonicClasspath()
+ {
+ List libDirs = [];
+
+ if (!string.IsNullOrWhiteSpace(_connection.MfClientLibPath))
+ {
+ libDirs.Add(_connection.MfClientLibPath.Trim());
+ }
+
+ if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
+ {
+ string home = _connection.SonicHome.Trim();
+ libDirs.Add(Path.Combine(home, "lib"));
+ libDirs.Add(home);
+ }
+
+ HashSet jars = new(StringComparer.OrdinalIgnoreCase);
+ foreach (string dir in libDirs.Where(Directory.Exists))
+ {
+ foreach (string jar in Directory.EnumerateFiles(dir, "*.jar", SearchOption.TopDirectoryOnly))
+ {
+ jars.Add(jar);
+ }
+ }
+
+ if (jars.Count == 0)
+ {
+ return (null,
+ "Keine Sonic-Client-JARs gefunden. MfClientLibPath oder SonicHome\\lib setzen "
+ + "(mgmt_client.jar, mfcontext.jar, …).");
+ }
+
+ // Explizite Kern-JARs zuerst, falls vorhanden
+ string[] preferred =
+ [
+ "mgmt_client.jar",
+ "mfcontext.jar",
+ "sonic_Client.jar",
+ "sonic_Crypto.jar",
+ "mf_common.jar"
+ ];
+
+ List ordered = [];
+ foreach (string name in preferred)
+ {
+ string? hit = jars.FirstOrDefault(j =>
+ string.Equals(Path.GetFileName(j), name, StringComparison.OrdinalIgnoreCase));
+ if (hit is not null)
+ {
+ ordered.Add(hit);
+ }
+ }
+
+ foreach (string jar in jars.OrderBy(Path.GetFileName, StringComparer.OrdinalIgnoreCase))
+ {
+ if (!ordered.Contains(jar, StringComparer.OrdinalIgnoreCase))
+ {
+ ordered.Add(jar);
+ }
+ }
+
+ return (string.Join(Path.PathSeparator, ordered), null);
+ }
+
+ private static string? ResolveToolsDir()
+ {
+ string[] dirs =
[
Path.Combine(AppContext.BaseDirectory, "Tools"),
Path.Combine(Directory.GetCurrentDirectory(), "Tools"),
AppContext.BaseDirectory
];
- foreach (string dir in searchDirs.Where(Directory.Exists))
+ foreach (string dir in dirs.Where(Directory.Exists))
{
- string classFile = Path.Combine(dir, "SonicMfContainerTool.class");
- if (File.Exists(classFile))
+ if (File.Exists(Path.Combine(dir, "SonicMfContainerTool.class")))
{
- int? major = ReadClassFileMajorVersion(classFile);
- // Alte Builds waren ~7KB; MBean-Stop-Tool ist >10KB.
- long len = new FileInfo(classFile).Length;
- if (major is not null && major <= runtimeMajor && len >= 10_000)
- {
- workDir = dir;
- classpathEntry = dir;
- return true;
- }
-
- if (major is not null && major <= runtimeMajor && len < 10_000)
- {
- error =
- $"Tools\\SonicMfContainerTool.class ist veraltet ({len} Bytes). Bitte neu bauen/pullen (erwartet >=10000).";
- continue;
- }
-
- error =
- $"Tools\\SonicMfContainerTool.class ist zu neu (major={major}, braucht <={runtimeMajor} / Java 8).";
- continue;
- }
-
- // JAR absichtlich nicht blind nutzen – oft noch mit Java 21 gebaut.
- // Nur .class mit geprüftem major<=runtimeMajor.
- }
-
- error ??= "Tools\\SonicMfContainerTool.class (Java 8) nicht gefunden.";
- return false;
- }
-
- private static int? ReadClassFileMajorVersion(string classFile)
- {
- try
- {
- byte[] header = new byte[8];
- using FileStream fs = File.OpenRead(classFile);
- if (fs.Read(header, 0, 8) < 8)
- {
- return null;
- }
-
- // CA FE BA BE | minor | major
- if (header[0] != 0xCA || header[1] != 0xFE || header[2] != 0xBA || header[3] != 0xBE)
- {
- return null;
- }
-
- return (header[6] << 8) | header[7];
- }
- catch
- {
- return null;
- }
- }
-
- private static async Task GetJavaClassMajorAsync(string javaExe, CancellationToken cancellationToken)
- {
- try
- {
- ProcessStartInfo psi = new()
- {
- FileName = javaExe,
- Arguments = "-version",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- using Process p = new() { StartInfo = psi };
- if (!p.Start())
- {
- return 0;
- }
-
- string err = await p.StandardError.ReadToEndAsync(cancellationToken);
- string output = await p.StandardOutput.ReadToEndAsync(cancellationToken);
- await p.WaitForExitAsync(cancellationToken);
- return ParseJavaVersionToClassMajor(err + "\n" + output);
- }
- catch
- {
- return 0;
- }
- }
-
- private static int ParseJavaVersionToClassMajor(string versionText)
- {
- string text = versionText.ToLowerInvariant();
-
- // 1.8.x → 52, 1.7.x → 51, 1.6.x → 50
- Match legacy = Regex.Match(text, @"version\s+""1\.(\d+)");
- if (legacy.Success && int.TryParse(legacy.Groups[1].Value, out int minor))
- {
- return 44 + minor; // 1.6→50, 1.7→51, 1.8→52
- }
-
- Match modern = Regex.Match(text, @"version\s+""(\d+)");
- if (modern.Success && int.TryParse(modern.Groups[1].Value, out int major) && major >= 9)
- {
- return 44 + major; // 9→53 … 21→65
- }
-
- return 0;
- }
-
- ///
- /// Sucht eine java.exe mit mindestens der gewünschten Class-Major-Version
- /// (für Tool-Bytecode Java 8 = 52), unabhängig von der alten Sonic-JRE.
- ///
- private async Task<(string? JavaExe, int Major, List Probed)> FindJavaWithMinimumMajorAsync(
- int minMajor,
- CancellationToken cancellationToken)
- {
- List probed = [];
- List candidates = [];
-
- void AddCandidate(string? path)
- {
- if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
- {
- return;
- }
-
- string full = Path.GetFullPath(path);
- if (!candidates.Contains(full, StringComparer.OrdinalIgnoreCase))
- {
- candidates.Add(full);
- }
- }
-
- foreach (string? configured in new[] { _connection.JavaPath, _connection.JavaHome })
- {
- if (string.IsNullOrWhiteSpace(configured)) continue;
- AddCandidate(ResolveToolFromConfiguredPath(configured, JavaExeName, probed));
- }
-
- foreach (string envName in new[] { "JAVA_HOME", "JRE_HOME", "JDK_HOME" })
- {
- AddCandidate(ResolveJavaFromHomeDir(Environment.GetEnvironmentVariable(envName), probed, envName));
- }
-
- AddCandidate(FindOnPath(JavaExeName, probed));
- AddCandidate(FindOnPath("java", probed));
- AddCandidate(FindJavaInWindowsRegistry(probed));
- AddCandidate(FindJavaViaWhereExe(probed));
- AddCandidate(FindJavaInCommonInstallLocations(probed));
-
- // Program Files Java/Adoptium/Temurin grob scannen
- foreach (string root in new[]
- {
- Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
- Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
- @"C:\Program Files\Eclipse Adoptium",
- @"C:\Program Files\Java",
- @"C:\Program Files\Microsoft",
- @"C:\Program Files\Amazon Corretto"
- })
- {
- if (!Directory.Exists(root)) continue;
- try
- {
- foreach (string javaExe in Directory.EnumerateFiles(root, "java.exe", SearchOption.AllDirectories)
- .Take(40))
- {
- AddCandidate(javaExe);
- }
- }
- catch
- {
- // ignore
- }
- }
-
- foreach (string candidate in candidates)
- {
- int major = await GetJavaClassMajorAsync(candidate, cancellationToken);
- probed.Add($"{candidate} => major={major}");
- if (major >= minMajor)
- {
- return (candidate, major, probed);
- }
- }
-
- return (null, 0, probed);
- }
-
- private static bool SupportsJavacRelease8(string javacPath)
- {
- try
- {
- using Process p = Process.Start(new ProcessStartInfo
- {
- FileName = javacPath,
- Arguments = "-version",
- UseShellExecute = false,
- RedirectStandardError = true,
- RedirectStandardOutput = true,
- CreateNoWindow = true
- })!;
- string text = (p.StandardError.ReadToEnd() + p.StandardOutput.ReadToEnd()).ToLowerInvariant();
- p.WaitForExit(5000);
- // javac 9+ supports --release
- return !text.Contains("1.8") && !text.Contains("1.7") && !text.Contains("1.6");
- }
- catch
- {
- return false;
- }
- }
-
- ///
- /// Baut einen Classpath mit echten Sonic-Management-Client-JARs
- /// (inkl. com.sonicsw.mf.jmx.client.JMSConnectorAddress).
- ///
- private (string? Classpath, string? Error) ResolveSonicClasspathDetailed()
- {
- List<(string Path, string Label)> searchRoots = [];
-
- if (!string.IsNullOrWhiteSpace(_connection.MfClientLibPath))
- {
- searchRoots.Add((_connection.MfClientLibPath.Trim().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))
- {
- searchRoots.Add((mqHome.Trim().Trim('"'), "MQ_HOME"));
- }
-
- if (!string.IsNullOrWhiteSpace(esbHome))
- {
- searchRoots.Add((esbHome.Trim().Trim('"'), "ESB_HOME/SONIC_HOME"));
- }
-
- if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
- {
- string sonicHome = _connection.SonicHome.Trim().Trim('"');
- searchRoots.Add((sonicHome, "SonicHome"));
- string? parent = Directory.GetParent(sonicHome)?.FullName;
- if (!string.IsNullOrWhiteSpace(parent))
- {
- searchRoots.Add((parent, "SonicHome-Parent"));
- }
- }
-
- List checkedPaths = [];
- HashSet seenDirs = new(StringComparer.OrdinalIgnoreCase);
- List markerHits = [];
-
- foreach ((string root, string label) in searchRoots)
- {
- if (string.IsNullOrWhiteSpace(root) || !Directory.Exists(root))
- {
- checkedPaths.Add($"{label}='{root}' (fehlt)");
- continue;
- }
-
- checkedPaths.Add($"{label}='{root}'");
-
- // 1) Bekannte Lib-Ordner
- List libCandidates = [root, Path.Combine(root, "lib"), .. EnumerateLikelyLibRoots(root)];
-
- // 2) Rekursiv nach Marker-JARs (SMC-only oft unter MQ*/lib oder Client/lib)
- foreach (string jar in EnumerateMarkerJars(root, maxDepth: 5, maxFiles: 400))
- {
- string? dir = Path.GetDirectoryName(jar);
- if (!string.IsNullOrWhiteSpace(dir))
- {
- libCandidates.Add(dir);
- markerHits.Add(jar);
- }
- }
-
- foreach (string libDir in libCandidates)
- {
- if (string.IsNullOrWhiteSpace(libDir) || !seenDirs.Add(libDir) || !Directory.Exists(libDir))
- {
- continue;
- }
-
- if (!DirectoryHasRequiredSonicClientJars(libDir, out string? detail))
- {
- if (!string.IsNullOrWhiteSpace(detail))
- {
- checkedPaths.Add($" skip '{libDir}': {detail}");
- }
-
- continue;
- }
-
- string? classpath = BuildClasspathFromLibDirs(CollectRelatedLibDirs(libDir, root));
- if (!string.IsNullOrWhiteSpace(classpath))
- {
- return (classpath, null);
- }
- }
- }
-
- string sonicHomeVal = _connection.SonicHome ?? string.Empty;
- string markerHint = markerHits.Count == 0
- ? "Keine Marker-JARs (mgmt_client/mfcontext/sonic_Client) gefunden."
- : "Marker-Treffer (unvollständig):\n - " + string.Join("\n - ", markerHits.Distinct(StringComparer.OrdinalIgnoreCase).Take(12));
-
- return (null,
- "Sonic-Client-JARs für MfApi fehlen (Class JMSConnectorAddress).\n" +
- $"Verwendetes SonicHome: '{(string.IsNullOrWhiteSpace(sonicHomeVal) ? "(leer)" : sonicHomeVal)}'\n" +
- "Benötigt u.a.: mgmt_client.jar, mfcontext.jar, sonic_Client.jar (Ordner mit *.jar).\n" +
- "Lösung: MfClientLibPath auf den Ordner setzen, in dem diese JARs liegen\n" +
- " (oft ...\\MQ10.0\\lib oder SMC-Client\\lib – nicht nur das JRE).\n" +
- markerHint + "\n" +
- "Geprüft:\n - " + string.Join("\n - ", checkedPaths.Take(40)));
- }
-
- private static IEnumerable EnumerateMarkerJars(string root, int maxDepth, int maxFiles)
- {
- if (!Directory.Exists(root))
- {
- yield break;
- }
-
- string[] markers =
- [
- "mgmt_client", "mfcontext", "sonic_Client", "sonic_client",
- "mf_client", "mf-client", "mgmt-client", "sonic_Crypto", "sonic_XA"
- ];
-
- Queue<(string Dir, int Depth)> queue = new();
- queue.Enqueue((root, 0));
- int yielded = 0;
- HashSet seen = new(StringComparer.OrdinalIgnoreCase);
-
- while (queue.Count > 0 && yielded < maxFiles)
- {
- (string dir, int depth) = queue.Dequeue();
- if (!seen.Add(dir))
- {
- continue;
- }
-
- IEnumerable files;
- try
- {
- files = Directory.EnumerateFiles(dir, "*.jar", SearchOption.TopDirectoryOnly);
- }
- catch
- {
- continue;
- }
-
- foreach (string file in files)
- {
- string name = Path.GetFileNameWithoutExtension(file);
- if (markers.Any(m => name.Contains(m, StringComparison.OrdinalIgnoreCase)))
- {
- yielded++;
- yield return file;
- if (yielded >= maxFiles)
- {
- yield break;
- }
- }
- }
-
- if (depth >= maxDepth)
- {
- continue;
- }
-
- IEnumerable children;
- try
- {
- children = Directory.EnumerateDirectories(dir);
- }
- catch
- {
- continue;
- }
-
- foreach (string child in children)
- {
- string leaf = Path.GetFileName(child);
- // Skip große / irrelevante Bäume
- if (leaf.Equals("docs", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("documentation", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("samples", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("log", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("logs", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("tmp", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("temp", StringComparison.OrdinalIgnoreCase)
- || leaf.StartsWith("jre", StringComparison.OrdinalIgnoreCase)
- || leaf.Equals("jdk", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- queue.Enqueue((child, depth + 1));
- }
- }
- }
-
- private static List CollectRelatedLibDirs(string primaryLibDir, string searchRoot)
- {
- HashSet dirs = new(StringComparer.OrdinalIgnoreCase) { primaryLibDir };
-
- // Sibling-Libs oft: MQ/lib + ESB/lib + common/lib
- string? parent = Directory.GetParent(primaryLibDir)?.FullName;
- if (!string.IsNullOrWhiteSpace(parent))
- {
- foreach (string sibling in new[]
- {
- Path.Combine(parent, "lib"),
- Path.Combine(parent, "common", "lib"),
- Path.Combine(parent, "client", "lib")
- })
- {
- if (Directory.Exists(sibling))
- {
- dirs.Add(sibling);
- }
- }
-
- string? grand = Directory.GetParent(parent)?.FullName;
- if (!string.IsNullOrWhiteSpace(grand))
- {
- foreach (string nested in EnumerateLikelyLibRoots(grand))
- {
- dirs.Add(nested);
- }
- }
- }
-
- if (Directory.Exists(searchRoot))
- {
- foreach (string nested in EnumerateLikelyLibRoots(searchRoot))
- {
- dirs.Add(nested);
- }
- }
-
- return dirs.Where(Directory.Exists).ToList();
- }
-
- private static string? BuildClasspathFromLibDirs(IEnumerable libDirs)
- {
- HashSet jarFiles = new(StringComparer.OrdinalIgnoreCase);
-
- foreach (string dir in libDirs)
- {
- if (!Directory.Exists(dir))
- {
- continue;
- }
-
- try
- {
- foreach (string jar in Directory.EnumerateFiles(dir, "*.jar", SearchOption.TopDirectoryOnly))
- {
- jarFiles.Add(jar);
- }
- }
- catch
- {
- // ignore unreadable dirs
- }
- }
-
- List entries = jarFiles
- .OrderBy(j => j, StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- if (entries.Count == 0)
- {
- return null;
- }
-
- // Classpath-Länge begrenzen: zu viele Einträge → CreateProcess-Fehler
- if (entries.Count > 250)
- {
- entries = entries.Take(250).ToList();
- }
-
- return string.Join(Path.PathSeparator, entries);
- }
-
- 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;
- }
- }
- }
- }
-
- ///
- /// Strikt: mindestens ein MF/Management-Client-JAR (nicht irgendein JAR-Ordner).
- ///
- private static bool DirectoryHasRequiredSonicClientJars(string path, out string? detail)
- {
- detail = null;
- try
- {
- string[] jars = Directory.EnumerateFiles(path, "*.jar", SearchOption.TopDirectoryOnly).ToArray();
- if (jars.Length == 0)
- {
- detail = "keine *.jar";
- return false;
- }
-
- string[] strong =
- [
- "mgmt_client", "mfcontext", "sonic_Client", "sonic_client", "mf_client", "mf-client"
- ];
-
- bool hasStrong = jars.Any(j =>
- strong.Any(m => Path.GetFileName(j).Contains(m, StringComparison.OrdinalIgnoreCase)));
-
- if (!hasStrong)
- {
- detail = $"{jars.Length} JARs, aber ohne mgmt_client/mfcontext/sonic_Client";
- return false;
- }
-
- return true;
- }
- catch (Exception ex)
- {
- detail = ex.Message;
- return false;
- }
- }
-
- private static string? ResolveToolSourcePath()
- {
- string[] candidates =
- [
- Path.Combine(AppContext.BaseDirectory, "Tools", "SonicMfContainerTool.java"),
- Path.Combine(Directory.GetCurrentDirectory(), "Tools", "SonicMfContainerTool.java"),
- Path.Combine(AppContext.BaseDirectory, "SonicMfContainerTool.java")
- ];
-
- return candidates.FirstOrDefault(File.Exists);
- }
-
- 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 })
- {
- if (string.IsNullOrWhiteSpace(configured))
- {
- continue;
- }
-
- string? fromConfig = ResolveToolFromConfiguredPath(configured, JavaExeName, checkedPaths);
- if (fromConfig is not null)
- {
- result.JavaExe = fromConfig;
- return result;
- }
- }
-
- foreach (string envName in new[] { "JAVA_HOME", "JRE_HOME", "JDK_HOME" })
- {
- 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, checkedPaths) ?? FindOnPath("java", checkedPaths);
- if (fromPath is not null)
- {
- result.JavaExe = fromPath;
- return result;
- }
-
- string? sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
- ? null
- : _connection.SonicHome.Trim();
-
- if (!string.IsNullOrWhiteSpace(sonicHome))
- {
- string? fromScripts = FindJavaFromSonicScripts(sonicHome, checkedPaths);
- if (fromScripts is not null)
- {
- result.JavaExe = fromScripts;
- return result;
- }
-
- 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)
- {
- 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;
- }
- }
- }
- }
-
- 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))
- {
- string sibling = Path.Combine(dir, javacName);
- if (File.Exists(sibling))
- {
- return sibling;
- }
- }
-
- foreach (string? configured in new[] { _connection.JavaPath, _connection.JavaHome })
- {
- string? fromConfig = ResolveToolFromConfiguredPath(configured, javacName, ignored);
- if (fromConfig is not null)
- {
- return fromConfig;
- }
- }
-
- foreach (string envName in new[] { "JAVA_HOME", "JDK_HOME" })
- {
- string? javaHome = Environment.GetEnvironmentVariable(envName);
- if (!string.IsNullOrWhiteSpace(javaHome))
- {
- string candidate = Path.Combine(javaHome.Trim().Trim('"'), "bin", javacName);
- if (File.Exists(candidate))
- {
- return candidate;
- }
- }
- }
-
- if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
- {
- foreach (string root in EnumerateJdkRootsUnderSonicHome(_connection.SonicHome))
- {
- string candidate = Path.Combine(root, "bin", javacName);
- if (File.Exists(candidate))
- {
- return candidate;
- }
- }
- }
-
- return FindOnPath(javacName, ignored) ?? FindOnPath("javac", ignored);
- }
-
- private static string? ResolveToolFromConfiguredPath(
- string? configured,
- string exeName,
- List checkedPaths)
- {
- if (string.IsNullOrWhiteSpace(configured))
- {
- return null;
- }
-
- string path = configured.Trim().Trim('"');
- NoteChecked(checkedPaths, $"config:{path}");
-
- if (File.Exists(path))
- {
- if (path.EndsWith(exeName, StringComparison.OrdinalIgnoreCase))
- {
- return path;
- }
-
- string? parent = Path.GetDirectoryName(path);
- if (!string.IsNullOrWhiteSpace(parent))
- {
- string sibling = Path.Combine(parent, exeName);
- NoteChecked(checkedPaths, sibling);
- if (File.Exists(sibling))
- {
- return sibling;
- }
- }
-
- string fileName = Path.GetFileName(path);
- if (fileName.Equals(Path.GetFileNameWithoutExtension(exeName), StringComparison.OrdinalIgnoreCase)
- || fileName.Equals(exeName, StringComparison.OrdinalIgnoreCase))
- {
- return path;
- }
- }
-
- string fromHome = Path.Combine(path, "bin", exeName);
- NoteChecked(checkedPaths, fromHome);
- return File.Exists(fromHome) ? fromHome : null;
- }
-
- private static string? ResolveJavaFromHomeDir(string? home, List checkedPaths, string label)
- {
- if (string.IsNullOrWhiteSpace(home))
- {
- NoteChecked(checkedPaths, $"{label}=(leer)");
- return 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? 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;
- }
-
- foreach (string root in EnumerateJdkRootsUnderSonicHome(sonicHome))
- {
- string candidate = Path.Combine(root, "bin", JavaExeName);
- NoteChecked(checkedPaths, candidate);
- if (File.Exists(candidate))
- {
- return candidate;
- }
- }
-
- return null;
- }
-
- private static IEnumerable EnumerateJdkRootsUnderSonicHome(string sonicHome)
- {
- if (!Directory.Exists(sonicHome))
- {
- yield break;
- }
-
- string[] preferredNames =
- [
- "jre", "jdk", "JRE", "JDK", "jre64", "jdk64", "Java", "java"
- ];
-
- foreach (string name in preferredNames)
- {
- string path = Path.Combine(sonicHome, name);
- if (Directory.Exists(path))
- {
- yield return path;
- string nestedJre = Path.Combine(path, "jre");
- if (Directory.Exists(nestedJre))
- {
- yield return nestedJre;
- }
- }
- }
-
- IEnumerable children;
- try
- {
- children = Directory.EnumerateDirectories(sonicHome);
- }
- catch
- {
- yield break;
- }
-
- foreach (string child in children)
- {
- foreach (string leaf in new[] { "jre", "jdk", "JRE", "JDK", "jre64", "jdk64" })
- {
- string nested = Path.Combine(child, leaf);
- if (Directory.Exists(nested))
- {
- yield return nested;
- }
- }
-
- string leafName = Path.GetFileName(child);
- if (leafName.StartsWith("jre", StringComparison.OrdinalIgnoreCase)
- || leafName.StartsWith("jdk", StringComparison.OrdinalIgnoreCase))
- {
- yield return child;
- }
- }
- }
-
- 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 =
- [
- Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
- Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
- @"C:\Program Files",
- @"C:\Program Files (x86)"
- ];
-
- string[] vendorFolders =
- [
- "Java",
- "Eclipse Adoptium",
- "AdoptOpenJDK",
- "Microsoft",
- "Amazon Corretto",
- "Zulu",
- "BellSoft",
- "Semeru",
- "Progress",
- "Aurea"
- ];
-
- foreach (string root in roots.Where(r => !string.IsNullOrWhiteSpace(r)).Distinct(StringComparer.OrdinalIgnoreCase))
- {
- foreach (string vendor in vendorFolders)
- {
- string vendorDir = Path.Combine(root, vendor);
- if (!Directory.Exists(vendorDir))
- {
- continue;
- }
-
- string direct = Path.Combine(vendorDir, "bin", JavaExeName);
- NoteChecked(checkedPaths, direct);
- if (File.Exists(direct))
- {
- return direct;
- }
-
- try
- {
- foreach (string sub in Directory.EnumerateDirectories(vendorDir)
- .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;
- }
- }
- }
- catch
- {
- // ignore inaccessible vendor dirs
- }
- }
- }
-
- 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, List checkedPaths)
- {
- string? pathEnv = Environment.GetEnvironmentVariable("PATH");
- if (string.IsNullOrWhiteSpace(pathEnv))
- {
- NoteChecked(checkedPaths, "PATH=(leer)");
- return null;
- }
-
- foreach (string dir in pathEnv.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries))
- {
- try
- {
- string candidate = Path.Combine(dir.Trim().Trim('"'), fileName);
- NoteChecked(checkedPaths, $"PATH:{candidate}");
- if (File.Exists(candidate))
- {
- return candidate;
- }
- }
- catch
- {
- // ignore bad PATH entries
+ return dir;
}
}
@@ -1927,29 +274,6 @@ public sealed class SonicMfApiExecutor
}
}
- return string.IsNullOrWhiteSpace(combined) ? null : Truncate(combined);
+ return null;
}
-
- private static string Quote(string value)
- => "\"" + value.Replace("\"", "\\\"") + "\"";
-
- private static string EscapeArg(string value)
- {
- if (value.Length == 0)
- {
- return "\"\"";
- }
-
- bool needsQuotes = value.Contains(' ') || value.Contains('\t') || value.Contains('"')
- || value.Contains('*') || value.Contains(';');
- if (!needsQuotes)
- {
- return value;
- }
-
- return "\"" + value.Replace("\"", "\\\"") + "\"";
- }
-
- private static string Truncate(string s, int max = 800)
- => s.Length <= max ? s : s[..max] + "…";
}
diff --git a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class
index d1c1955..980efa7 100644
Binary files a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class and b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class differ
diff --git a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.class b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.class
index 105c868..8898afe 100644
Binary files a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.class and b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.class differ
diff --git a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.java b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.java
index 2f1caaa..a96c522 100644
--- a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.java
+++ b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.java
@@ -1,27 +1,15 @@
import java.lang.reflect.Method;
import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Set;
-import javax.management.MBeanOperationInfo;
-import javax.management.MBeanInfo;
import javax.management.ObjectName;
/**
- * Sonic Management Application API helper (same restart intent as SMC).
- *
- * TOOL_VERSION is printed first so we can verify the deployed build.
- *
- * Remote JMSConnectorClient is "unbounded". IAgentProxy.restart() often throws
- * "Operation unsupported for unbounded client connector". SMC Restart typically
- * stops the agent via JMX; Launch Daemon brings it back.
- *
+ * Minimaler Sonic-Restart (wie SMC): JMSConnectorClient + MBean stop/restart.
* Compile: javac --release 8 SonicMfContainerTool.java
*/
public final class SonicMfContainerTool
{
- /** Bump when restart logic changes – must appear in app output. */
- public static final String TOOL_VERSION = "2026-07-24c-mbean-stop";
+ public static final String TOOL_VERSION = "2026-07-24d-restart-only";
public static void main(String[] args)
{
@@ -29,21 +17,14 @@ public final class SonicMfContainerTool
try
{
Args a = Args.parse(args);
- if (a.command == null)
+ if (!"restart".equals(a.command))
{
- fail("Usage: SonicMfContainerTool ping|list|restart --domain D --url U --user U [--password P] [--container C] [--timeout SEC]");
+ fail("Usage: SonicMfContainerTool restart --domain D --url U --user U --container C [--timeout SEC]");
return;
}
-
- if (isBlank(a.domain) || isBlank(a.url) || isBlank(a.user))
+ if (isBlank(a.domain) || isBlank(a.url) || isBlank(a.user) || isBlank(a.container))
{
- fail("domain, url und user sind Pflicht.");
- return;
- }
-
- if ("restart".equals(a.command) && isBlank(a.container))
- {
- fail("restart erfordert --container.");
+ fail("domain, url, user und container sind Pflicht.");
return;
}
@@ -51,22 +32,7 @@ public final class SonicMfContainerTool
Object connector = connect(a.url, a.user, a.password, timeoutMs);
try
{
- if ("ping".equals(a.command))
- {
- ping(connector, a.domain);
- }
- else if ("list".equals(a.command))
- {
- list(connector, a.domain);
- }
- else if ("restart".equals(a.command))
- {
- restart(connector, a.domain, a.container);
- }
- else
- {
- fail("Unbekannter Befehl: " + a.command);
- }
+ restart(connector, a.domain, a.container);
}
finally
{
@@ -86,8 +52,7 @@ public final class SonicMfContainerTool
}
}
- private static Object connect(String url, String user, String password, long timeoutMs)
- throws Exception
+ private static Object connect(String url, String user, String password, long timeoutMs) throws Exception
{
Hashtable env = new Hashtable();
env.put("ConnectionURLs", url);
@@ -99,8 +64,6 @@ public final class SonicMfContainerTool
Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient");
Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {});
-
- // Optional: Request-Timeout setzen (falls vorhanden)
trySetTimeout(connector, timeoutMs);
Method connect = findConnect(clientCl);
@@ -111,199 +74,34 @@ public final class SonicMfContainerTool
}
Class[] pts = connect.getParameterTypes();
- Object[] callArgs;
if (pts.length == 2)
{
- callArgs = new Object[] { address, boxTimeout(pts[1], timeoutMs) };
- }
- else if (pts.length == 1)
- {
- callArgs = new Object[] { address };
+ connect.invoke(connector, new Object[] { address, boxTimeout(pts[1], timeoutMs) });
}
else
{
- callArgs = new Object[] { address, boxTimeout(pts[1], timeoutMs) };
+ connect.invoke(connector, new Object[] { address });
}
-
- connect.invoke(connector, callArgs);
- info("Connected url=" + url + " user=" + user);
return connector;
}
- private static Method findConnect(Class clientCl)
- {
- Method best = null;
- Method[] methods = clientCl.getMethods();
- for (int i = 0; i < methods.length; i++)
- {
- Method m = methods[i];
- if (!"connect".equals(m.getName()))
- {
- continue;
- }
- if (m.getParameterTypes().length == 2)
- {
- return m;
- }
- if (m.getParameterTypes().length == 1)
- {
- best = m;
- }
- }
- return best;
- }
-
- private static void trySetTimeout(Object connector, long timeoutMs)
- {
- String[] names = new String[] { "setTimeout", "setRequestTimeout", "setDefaultTimeout" };
- for (int i = 0; i < names.length; i++)
- {
- try
- {
- Method m = connector.getClass().getMethod(names[i], new Class[] { Long.TYPE });
- m.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
- info("Set " + names[i] + "=" + timeoutMs);
- return;
- }
- catch (NoSuchMethodException ignore)
- {
- try
- {
- Method m = connector.getClass().getMethod(names[i], new Class[] { Integer.TYPE });
- m.invoke(connector, new Object[] { Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs)) });
- info("Set " + names[i] + "=" + timeoutMs);
- return;
- }
- catch (Exception ignore2)
- {
- /* next */
- }
- }
- catch (Exception ignore)
- {
- /* next */
- }
- }
- }
-
- private static Object boxTimeout(Class type, long timeoutMs)
- {
- if (type == Long.TYPE || type == Long.class)
- {
- return Long.valueOf(timeoutMs);
- }
- if (type == Integer.TYPE || type == Integer.class)
- {
- return Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
- }
- return Long.valueOf(timeoutMs);
- }
-
- private static void ping(Object connector, String domain) throws Exception
- {
- Set names = queryAgents(connector);
- int matched = 0;
- if (names != null)
- {
- for (Iterator it = names.iterator(); it.hasNext(); )
- {
- ObjectName on = (ObjectName) it.next();
- if (extractContainer(on, domain) != null)
- {
- matched++;
- }
- }
- }
- System.out.println("OK:MfApiPing domain=" + domain + " agents=" + matched);
- System.out.flush();
- }
-
- private static void list(Object connector, String domain) throws Exception
- {
- Set names = queryAgents(connector);
- int count = 0;
- if (names != null)
- {
- for (Iterator it = names.iterator(); it.hasNext(); )
- {
- ObjectName on = (ObjectName) it.next();
- String container = extractContainer(on, domain);
- if (container != null)
- {
- System.out.println(container);
- count++;
- }
- }
- }
- if (count == 0)
- {
- info("KeineAgentContainer Domain=" + domain);
- }
- System.out.println("OK:List count=" + count);
- System.out.flush();
- }
-
private static void restart(Object connector, String domain, String container) throws Exception
{
String shortName = shortContainer(container);
- // Zuerst Preferred-ObjectName OHNE queryNames – query kann schon scheitern/irreführen
- ObjectName preferred = new ObjectName(domain + "." + shortName + ":ID=AGENT");
- info("PreferredObjectName=" + preferred);
-
- ObjectName on = preferred;
- try
- {
- ObjectName resolved = resolveAgentObjectName(connector, domain, shortName);
- if (resolved != null)
- {
- on = resolved;
- }
- }
- catch (Throwable t)
- {
- warn("resolveAgentObjectName: " + rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage()
- + " – nutze PreferredObjectName");
- }
+ ObjectName on = new ObjectName(domain + "." + shortName + ":ID=AGENT");
info("ObjectName=" + on);
- dumpOpsSafe(connector, on);
-
StringBuffer attempts = new StringBuffer();
-
- // 1) JMX invoke stop/restart/shutdown (remote / wie SMC)
- if (tryMBeanLifecycle(connector, on, shortName, domain, attempts))
- {
- return;
- }
-
- // 2) IAgentProxy stop/restart
- if (tryAgentProxyLifecycle(connector, on, shortName, domain, attempts))
- {
- return;
- }
-
- // 3) Manager-MBeans mit Container-Namen
- if (tryManagerContainerOps(connector, domain, shortName, attempts))
- {
- return;
- }
-
- fail("Kein Neustart-Weg erfolgreich. ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString());
- }
-
- private static boolean tryMBeanLifecycle(
- Object connector, ObjectName on, String shortName, String domain, StringBuffer attempts)
- {
- String[] ops = new String[] { "stop", "restart", "shutdown" };
+ String[] ops = new String[] { "stop", "restart" };
for (int i = 0; i < ops.length; i++)
{
String op = ops[i];
try
{
- info("Trying MBean.invoke(" + op + ") on " + on);
+ info("Trying MBean.invoke(" + op + ")");
invokeNoArgs(connector, on, op);
okRestart("MBean." + op, shortName, domain);
- return true;
+ return;
}
catch (Throwable t)
{
@@ -311,162 +109,23 @@ public final class SonicMfContainerTool
String line = "MBean." + op + " => " + root.getClass().getName() + ": " + root.getMessage();
warn(line);
attempts.append(line).append('\n');
-
- // stop kann die Verbindung reissen – wenn Message darauf hindeutet, als Erfolg werten
if ("stop".equals(op) && looksLikeStopSideEffect(root))
{
- warn("Treat stop side-effect as success (agent going down)");
okRestart("MBean.stop(side-effect)", shortName, domain);
- return true;
+ return;
}
}
}
- return false;
+
+ fail("Neustart fehlgeschlagen. ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString());
}
- private static boolean tryAgentProxyLifecycle(
- Object connector, ObjectName on, String shortName, String domain, StringBuffer attempts)
+ private static void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception
{
- try
- {
- Class factoryCl = Class.forName("com.sonicsw.mf.mgmtapi.runtime.MFProxyFactory");
- Method create = factoryCl.getMethod("createAgentProxy", new Class[] {
- Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient"),
- ObjectName.class
- });
- Object agent = create.invoke(null, new Object[] { connector, on });
- info("StateBefore=" + safeState(agent));
-
- String[] methods = new String[] { "stop", "restart", "shutdown" };
- for (int i = 0; i < methods.length; i++)
- {
- String mName = methods[i];
- try
- {
- info("Trying IAgentProxy." + mName);
- agent.getClass().getMethod(mName).invoke(agent);
- okRestart("IAgentProxy." + mName, shortName, domain);
- return true;
- }
- catch (Throwable t)
- {
- Throwable root = rootOf(t);
- String line = "IAgentProxy." + mName + " => " + root.getClass().getName() + ": " + root.getMessage();
- warn(line);
- attempts.append(line).append('\n');
- if ("stop".equals(mName) && looksLikeStopSideEffect(root))
- {
- okRestart("IAgentProxy.stop(side-effect)", shortName, domain);
- return true;
- }
- }
- }
- }
- catch (Throwable t)
- {
- Throwable root = rootOf(t);
- String line = "IAgentProxy path => " + root.getClass().getName() + ": " + root.getMessage();
- warn(line);
- attempts.append(line).append('\n');
- }
- return false;
- }
-
- private static boolean tryManagerContainerOps(
- Object connector, String domain, String shortName, StringBuffer attempts)
- {
- String[] candidates = new String[] {
- domain + ".DomainManager:ID=DomainManager",
- domain + ".DomainManager:ID=AGENT",
- domain + ".dm:ID=AGENT"
- };
-
- for (int i = 0; i < candidates.length; i++)
- {
- try
- {
- ObjectName pattern = new ObjectName(candidates[i]);
- Set found = queryNames(connector, pattern);
- if (found == null || found.isEmpty())
- {
- continue;
- }
- ObjectName real = (ObjectName) found.iterator().next();
- info("Manager=" + real);
- dumpOpsSafe(connector, real);
-
- String[] ops = new String[] { "restartContainer", "stopContainer", "startContainer" };
- for (int o = 0; o < ops.length; o++)
- {
- try
- {
- info("Trying " + ops[o] + "(\"" + shortName + "\") on " + real);
- invokeStringArg(connector, real, ops[o], shortName);
- okRestart("Manager." + ops[o], shortName, domain);
- return true;
- }
- catch (Throwable t)
- {
- Throwable root = rootOf(t);
- String line = ops[o] + " => " + root.getClass().getName() + ": " + root.getMessage();
- warn(line);
- attempts.append(line).append('\n');
- }
- }
- }
- catch (Throwable t)
- {
- warn("Manager candidate " + candidates[i] + ": " + rootOf(t).getMessage());
- }
- }
-
- // Scan AGENT-MBeans nach Container-Ops
- try
- {
- Set agents = queryAgents(connector);
- if (agents == null)
- {
- return false;
- }
- for (Iterator it = agents.iterator(); it.hasNext(); )
- {
- ObjectName on = (ObjectName) it.next();
- String jmxDomain = on.getDomain();
- if (jmxDomain == null)
- {
- continue;
- }
- String lower = jmxDomain.toLowerCase();
- if (!(lower.contains("domainmanager") || lower.contains(".dm")
- || lower.contains("collector") || lower.contains("host")
- || lower.contains("launch")))
- {
- continue;
- }
- info("Scan manager agent " + on);
- dumpOpsSafe(connector, on);
- String[] ops = new String[] { "restartContainer", "stopContainer" };
- for (int i = 0; i < ops.length; i++)
- {
- try
- {
- invokeStringArg(connector, on, ops[i], shortName);
- okRestart(ops[i] + "@" + on, shortName, domain);
- return true;
- }
- catch (Throwable t)
- {
- attempts.append(ops[i]).append('@').append(on).append(" => ")
- .append(rootOf(t).getMessage()).append('\n');
- }
- }
- }
- }
- catch (Throwable t)
- {
- warn("Manager scan: " + rootOf(t).getMessage());
- }
- return false;
+ Method invoke = connector.getClass().getMethod("invoke", new Class[] {
+ ObjectName.class, String.class, Object[].class, String[].class
+ });
+ invoke.invoke(connector, new Object[] { on, op, new Object[0], new String[0] });
}
private static boolean looksLikeStopSideEffect(Throwable root)
@@ -479,8 +138,7 @@ public final class SonicMfContainerTool
return m.indexOf("disconnect") >= 0
|| m.indexOf("closed") >= 0
|| m.indexOf("not connected") >= 0
- || m.indexOf("connection lost") >= 0
- || m.indexOf("broker") >= 0 && m.indexOf("down") >= 0;
+ || m.indexOf("connection lost") >= 0;
}
private static void okRestart(String method, String shortName, String domain)
@@ -491,172 +149,75 @@ public final class SonicMfContainerTool
System.out.flush();
}
- private static void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception
+ private static Method findConnect(Class clientCl)
{
- Method invoke = connector.getClass().getMethod("invoke", new Class[] {
- ObjectName.class, String.class, Object[].class, String[].class
- });
- invoke.invoke(connector, new Object[] { on, op, new Object[0], new String[0] });
+ Method[] methods = clientCl.getMethods();
+ Method best = null;
+ for (int i = 0; i < methods.length; i++)
+ {
+ Method m = methods[i];
+ if (!"connect".equals(m.getName()))
+ {
+ continue;
+ }
+ Class[] pts = m.getParameterTypes();
+ if (pts.length == 1 || pts.length == 2)
+ {
+ best = m;
+ if (pts.length == 2)
+ {
+ return m;
+ }
+ }
+ }
+ return best;
}
- private static void invokeStringArg(Object connector, ObjectName on, String op, String arg) throws Exception
- {
- Method invoke = connector.getClass().getMethod("invoke", new Class[] {
- ObjectName.class, String.class, Object[].class, String[].class
- });
- invoke.invoke(connector, new Object[] {
- on, op, new Object[] { arg }, new String[] { "java.lang.String" }
- });
- }
-
- private static void dumpOpsSafe(Object connector, ObjectName on)
+ private static void trySetTimeout(Object connector, long timeoutMs)
{
try
{
- Method getInfo = connector.getClass().getMethod("getMBeanInfo", new Class[] { ObjectName.class });
- MBeanInfo infoBean = (MBeanInfo) getInfo.invoke(connector, new Object[] { on });
- if (infoBean == null || infoBean.getOperations() == null)
+ connector.getClass().getMethod("setTimeout", new Class[] { Long.TYPE })
+ .invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
+ }
+ catch (Exception ignore)
+ {
+ try
{
- info("Ops(" + on + ")=(null)");
- return;
+ connector.getClass().getMethod("setRequestTimeout", new Class[] { Long.TYPE })
+ .invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
}
- StringBuffer sb = new StringBuffer();
- MBeanOperationInfo[] ops = infoBean.getOperations();
- for (int i = 0; i < ops.length; i++)
+ catch (Exception ignore2)
{
- String name = ops[i].getName();
- String lower = name.toLowerCase();
- if (lower.indexOf("restart") >= 0 || lower.indexOf("stop") >= 0
- || lower.indexOf("start") >= 0 || lower.indexOf("shutdown") >= 0
- || lower.indexOf("container") >= 0)
- {
- if (sb.length() > 0)
- {
- sb.append(',');
- }
- sb.append(name);
- }
- }
- info("Ops(" + on + ")=" + (sb.length() == 0 ? "(keine lifecycle)" : sb.toString()));
- }
- catch (Throwable t)
- {
- warn("getMBeanInfo(" + on + "): " + rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage());
- }
- }
-
- private static Set queryAgents(Object connector) throws Exception
- {
- return queryNames(connector, new ObjectName("*:ID=AGENT"));
- }
-
- private static Set queryNames(Object connector, ObjectName pattern) throws Exception
- {
- Method query = connector.getClass().getMethod("queryNames", new Class[] {
- ObjectName.class, javax.management.QueryExp.class
- });
- return (Set) query.invoke(connector, new Object[] { pattern, null });
- }
-
- private static ObjectName resolveAgentObjectName(Object connector, String domain, String container)
- throws Exception
- {
- ObjectName preferred = new ObjectName(domain + "." + container + ":ID=AGENT");
- Set exact = queryNames(connector, preferred);
- if (exact != null && !exact.isEmpty())
- {
- return (ObjectName) exact.iterator().next();
- }
-
- Set names = queryAgents(connector);
- if (names != null)
- {
- for (Iterator it = names.iterator(); it.hasNext(); )
- {
- ObjectName on = (ObjectName) it.next();
- String c = extractContainer(on, domain);
- if (c != null && c.equalsIgnoreCase(container))
- {
- return on;
- }
+ /* optional */
}
}
- return preferred;
}
- private static String extractContainer(ObjectName on, String domain)
+ private static Object boxTimeout(Class type, long timeoutMs)
{
- if (on == null || isBlank(domain))
+ if (type == Integer.TYPE || type == Integer.class)
{
- return null;
+ return Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
}
- String jmxDomain = on.getDomain();
- if (jmxDomain == null)
- {
- return null;
- }
- String prefix = domain + ".";
- if (jmxDomain.regionMatches(true, 0, prefix, 0, prefix.length()))
- {
- return jmxDomain.substring(prefix.length());
- }
- return null;
+ return Long.valueOf(timeoutMs);
}
private static String shortContainer(String container)
{
- if (container == null)
- {
- return "";
- }
- int dot = container.indexOf('.');
- if (dot >= 0 && dot < container.length() - 1)
- {
- return container.substring(dot + 1);
- }
- return container;
- }
-
- private static String safeState(Object agent)
- {
- try
- {
- Object s = agent.getClass().getMethod("getStateString").invoke(agent);
- return s == null ? "?" : String.valueOf(s);
- }
- catch (Throwable t)
- {
- return "?";
- }
+ String c = container.trim();
+ int dot = c.lastIndexOf('.');
+ return dot >= 0 ? c.substring(dot + 1) : c;
}
private static Throwable rootOf(Throwable t)
{
- Throwable root = t;
- while (root != null && root.getCause() != null && root.getCause() != root)
+ Throwable cur = t;
+ while (cur.getCause() != null && cur.getCause() != cur)
{
- root = root.getCause();
+ cur = cur.getCause();
}
- return root == null ? t : root;
- }
-
- private static void info(String message)
- {
- System.out.println("INFO:" + message);
- System.out.flush();
- }
-
- private static void warn(String message)
- {
- System.out.println("WARN:" + message);
- System.out.flush();
- }
-
- private static void fail(String message)
- {
- System.err.println("ERROR:" + message);
- System.err.flush();
- System.exit(2);
+ return cur;
}
private static boolean isBlank(String s)
@@ -664,6 +225,25 @@ public final class SonicMfContainerTool
return s == null || s.trim().length() == 0;
}
+ private static void info(String msg)
+ {
+ System.out.println("INFO:" + msg);
+ System.out.flush();
+ }
+
+ private static void warn(String msg)
+ {
+ System.out.println("WARN:" + msg);
+ System.out.flush();
+ }
+
+ private static void fail(String msg)
+ {
+ System.err.println("ERROR:" + msg);
+ System.err.flush();
+ System.exit(1);
+ }
+
private static final class Args
{
String command;
@@ -681,27 +261,22 @@ public final class SonicMfContainerTool
{
return a;
}
-
- a.command = args[0].toLowerCase();
+ a.command = args[0];
for (int i = 1; i < args.length; i++)
{
- String key = args[i];
- if (!key.startsWith("--") || i + 1 >= args.length)
+ String k = args[i];
+ String v = (i + 1 < args.length) ? args[i + 1] : null;
+ if ("--domain".equals(k) && v != null) { a.domain = v; i++; }
+ else if ("--url".equals(k) && v != null) { a.url = v; i++; }
+ else if ("--user".equals(k) && v != null) { a.user = v; i++; }
+ else if ("--password".equals(k) && v != null) { a.password = v; i++; }
+ else if ("--container".equals(k) && v != null) { a.container = v; i++; }
+ else if ("--timeout".equals(k) && v != null)
{
- continue;
- }
- String val = args[++i];
- if ("--domain".equals(key)) a.domain = val;
- else if ("--url".equals(key)) a.url = val;
- else if ("--user".equals(key)) a.user = val;
- else if ("--password".equals(key)) a.password = val;
- else if ("--container".equals(key)) a.container = val;
- else if ("--timeout".equals(key))
- {
- try { a.timeoutSec = Integer.parseInt(val); } catch (Exception ignore) { /* keep */ }
+ try { a.timeoutSec = Integer.parseInt(v); } catch (Exception ignore) { /* keep default */ }
+ i++;
}
}
-
if (isBlank(a.password))
{
String env = System.getenv("ESB_SONIC_PASSWORD");
@@ -713,4 +288,8 @@ public final class SonicMfContainerTool
return a;
}
}
+
+ private SonicMfContainerTool()
+ {
+ }
}
diff --git a/ZA.CoreService.ESBCertificateManager/appsettings.json b/ZA.CoreService.ESBCertificateManager/appsettings.json
index f807e9d..c04690e 100644
--- a/ZA.CoreService.ESBCertificateManager/appsettings.json
+++ b/ZA.CoreService.ESBCertificateManager/appsettings.json
@@ -7,7 +7,6 @@
"ConnectionUrl": "tcp://dekun-painwbdet:13070",
"Username": "Administrator",
"Password": "Administrator",
- "ManagementMode": "MfApi",
"SonicHome": "C:\\DEV\\MQ10.0",
"JavaHome": "C:\\Program Files (x86)\\Java\\jre1.8.0_501",
"JavaPath": "C:\\Program Files (x86)\\Java\\jre1.8.0_501\\bin\\java.exe",