Fix Java 8 resolution for MfApi restart, refresh targets after settings, and copy errors to clipboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 09:34:04 +02:00
co-authored by Cursor
parent f584fd68fe
commit dcceb7b719
14 changed files with 358 additions and 97 deletions
@@ -0,0 +1,135 @@
namespace ZA.CoreService.ESBCertificateManager.Services;
/// <summary>
/// Fehlerdialog mit Text und Button „In Zwischenablage kopieren“.
/// Kopiert den Fehlertext beim Öffnen automatisch.
/// </summary>
public static class CopyableErrorDialog
{
public static void Show(
IWin32Window? owner,
string title,
string details)
{
string text = string.IsNullOrWhiteSpace(details)
? "(keine Fehlerdetails)"
: details.Trim();
TryCopy(text);
using Form dialog = new()
{
Text = title,
StartPosition = FormStartPosition.CenterParent,
FormBorderStyle = FormBorderStyle.FixedDialog,
MaximizeBox = false,
MinimizeBox = false,
ShowInTaskbar = false,
ClientSize = new Size(640, 420),
BackColor = Color.FromArgb(16, 28, 48),
ForeColor = Color.FromArgb(241, 245, 249),
Font = new Font("Segoe UI", 9.5f)
};
Label hint = new()
{
Text =
"Fehlertext ist in der Zwischenablage — "
+ "einfach hier einfügen (Strg+V).",
Location = new Point(16, 12),
AutoSize = false,
Size = new Size(608, 28),
ForeColor = Color.FromArgb(208, 171, 57)
};
TextBox box = new()
{
Location = new Point(16, 44),
Size = new Size(608, 310),
Multiline = true,
ReadOnly = true,
ScrollBars = ScrollBars.Both,
WordWrap = false,
Text = text,
BackColor = Color.FromArgb(12, 22, 38),
ForeColor = Color.FromArgb(241, 245, 249),
BorderStyle = BorderStyle.FixedSingle,
Font = new Font("Consolas", 9f)
};
Label copyStatus = new()
{
Text = "✓ In Zwischenablage kopiert",
Location = new Point(16, 368),
AutoSize = true,
ForeColor = Color.FromArgb(90, 200, 140)
};
Button btnCopy = new()
{
Text = "Nochmal kopieren",
Location = new Point(280, 362),
Size = new Size(160, 36),
FlatStyle = FlatStyle.Flat,
BackColor = Color.FromArgb(39, 52, 73),
ForeColor = Color.FromArgb(241, 245, 249),
Cursor = Cursors.Hand
};
btnCopy.FlatAppearance.BorderColor =
Color.FromArgb(36, 74, 117);
btnCopy.Click += (_, _) =>
{
if (TryCopy(text))
{
copyStatus.Text = "✓ Erneut kopiert";
copyStatus.ForeColor =
Color.FromArgb(90, 200, 140);
}
else
{
copyStatus.Text = "Kopieren fehlgeschlagen";
copyStatus.ForeColor =
Color.FromArgb(220, 100, 100);
}
};
Button btnClose = new()
{
Text = "Schließen",
Location = new Point(456, 362),
Size = new Size(168, 36),
FlatStyle = FlatStyle.Flat,
BackColor = Color.FromArgb(0, 110, 182),
ForeColor = Color.White,
Cursor = Cursors.Hand,
DialogResult = DialogResult.OK
};
btnClose.FlatAppearance.BorderSize = 0;
dialog.Controls.Add(hint);
dialog.Controls.Add(box);
dialog.Controls.Add(copyStatus);
dialog.Controls.Add(btnCopy);
dialog.Controls.Add(btnClose);
dialog.AcceptButton = btnClose;
dialog.CancelButton = btnClose;
dialog.ShowDialog(owner);
}
private static bool TryCopy(string text)
{
try
{
Clipboard.SetText(text);
return true;
}
catch
{
return false;
}
}
}
@@ -0,0 +1,121 @@
namespace ZA.CoreService.ESBCertificateManager.Services;
/// <summary>
/// Findet eine nutzbare Java-8-Runtime für Sonic MfApi.
/// </summary>
public static class JavaRuntimeLocator
{
public static string? Resolve(
string? configuredPath = null)
{
foreach (string? candidate in EnumerateCandidates(configuredPath))
{
if (string.IsNullOrWhiteSpace(candidate))
{
continue;
}
string? resolved = TryResolveExisting(candidate);
if (resolved is not null)
{
return resolved;
}
}
return null;
}
private static IEnumerable<string?> EnumerateCandidates(
string? configuredPath)
{
if (!string.IsNullOrWhiteSpace(configuredPath))
{
yield return configuredPath.Trim();
}
yield return
@"C:\Program Files (x86)\Java\jre1.8.0_481\bin\java.exe";
yield return
@"C:\Program Files (x86)\Java\jre1.8.0_501\bin\java.exe";
yield return
@"C:\Program Files\Java\jre1.8.0_481\bin\java.exe";
yield return
@"C:\Program Files (x86)\Common Files\Oracle\Java\java8path\java.exe";
foreach (string root in new[]
{
@"C:\Program Files (x86)\Java",
@"C:\Program Files\Java"
})
{
if (!Directory.Exists(root))
{
continue;
}
foreach (string directory in Directory
.EnumerateDirectories(root, "jre1.8*")
.OrderByDescending(path => path, StringComparer.OrdinalIgnoreCase))
{
yield return Path.Combine(directory, "bin", "java.exe");
}
foreach (string directory in Directory
.EnumerateDirectories(root, "jdk1.8*")
.OrderByDescending(path => path, StringComparer.OrdinalIgnoreCase))
{
yield return Path.Combine(directory, "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";
}
private static string? TryResolveExisting(string candidate)
{
try
{
string resolved =
Path.IsPathRooted(candidate)
? Path.GetFullPath(candidate)
: Path.GetFullPath(
Path.Combine(
AppContext.BaseDirectory,
candidate));
return File.Exists(resolved)
? resolved
: null;
}
catch
{
return null;
}
}
}
@@ -27,7 +27,9 @@ public sealed class RestartExecutor
if (connection is null)
{
return (false, "Sonic-Verbindung nicht gefunden",
$"Ziel '{target.Name}': SonicConnection '{target.SonicConnectionName}' fehlt in appsettings.");
$"Ziel '{target.Name}': SonicConnection '{target.SonicConnectionName}' "
+ "ist nicht geladen. Meist fehlt ein Benutzerprofil "
+ "(Einstellungen → Profil anlegen und übernehmen).");
}
using SonicManagementClient client =
@@ -11,8 +11,8 @@ public sealed class RuntimeEnvironmentValidator
{
List<string> issues = [];
string javaExecutablePath =
PathResolver.ResolvePath(
string? javaExecutablePath =
JavaRuntimeLocator.Resolve(
settings.JavaExecutablePath);
string sonicClientLibraryPath =
@@ -21,10 +21,11 @@ public sealed class RuntimeEnvironmentValidator
string javaVersion = string.Empty;
if (!File.Exists(javaExecutablePath))
if (javaExecutablePath is null)
{
issues.Add(
$"Java wurde nicht gefunden: {javaExecutablePath}");
"Java 8 wurde nicht gefunden. "
+ "Runtime:JavaExecutablePath oder installierte jre1.8* prüfen.");
}
else
{
@@ -80,7 +81,7 @@ public sealed class RuntimeEnvironmentValidator
return new RuntimeValidationResult
{
IsValid = issues.Count == 0,
JavaExecutablePath = javaExecutablePath,
JavaExecutablePath = javaExecutablePath ?? string.Empty,
SonicClientLibraryPath = sonicClientLibraryPath,
JavaVersion = javaVersion,
Issues = issues
@@ -44,8 +44,8 @@ public sealed class SonicCredentialTester
"Für den Verbindungstest fehlt ein Container.");
}
string javaPath =
PathResolver.ResolvePath(
string? javaPath =
JavaRuntimeLocator.Resolve(
_runtimeSettings.JavaExecutablePath);
string libraryPath =
@@ -55,10 +55,12 @@ public sealed class SonicCredentialTester
string? toolsPath =
ResolveToolsDirectory();
if (!File.Exists(javaPath))
if (javaPath is null)
{
return CredentialTestResult.Failed(
$"Java wurde nicht gefunden: {javaPath}");
"Java 8 wurde nicht gefunden. "
+ "Runtime:JavaExecutablePath prüfen "
+ @"(z. B. C:\Program Files (x86)\Java\jre1.8.0_481\bin\java.exe).");
}
if (!Directory.Exists(libraryPath))
@@ -356,84 +356,35 @@ public sealed class SonicMfApiExecutor
private string? ResolveJavaExe()
{
foreach (string? candidate
in EnumerateJavaCandidates())
// Explizite Verbindungs-Pfade zuerst, dann Java-8-Suche
// (Runtime\bin\java.exe fehlt oft; JAVA_HOME zeigt oft auf JDK 21).
string? fromConnection = JavaRuntimeLocator.Resolve(
!string.IsNullOrWhiteSpace(_connection.JavaPath)
? _connection.JavaPath
: null);
if (fromConnection is not null)
{
if (string.IsNullOrWhiteSpace(candidate))
{
continue;
}
string resolvedCandidate;
try
{
resolvedCandidate =
Path.IsPathRooted(candidate)
? Path.GetFullPath(candidate)
: Path.GetFullPath(
Path.Combine(
AppContext.BaseDirectory,
candidate));
}
catch
{
continue;
}
if (File.Exists(resolvedCandidate))
{
return resolvedCandidate;
}
return fromConnection;
}
return null;
}
private IEnumerable<string?>
EnumerateJavaCandidates()
{
if (!string.IsNullOrWhiteSpace(
_connection.JavaPath))
if (!string.IsNullOrWhiteSpace(_connection.JavaHome))
{
yield return
_connection.JavaPath.Trim();
}
if (!string.IsNullOrWhiteSpace(
_connection.JavaHome))
{
yield return Path.Combine(
string fromHome = Path.Combine(
_connection.JavaHome.Trim(),
"bin",
"java.exe");
string? resolvedHome =
JavaRuntimeLocator.Resolve(fromHome);
if (resolvedHome is not null)
{
return resolvedHome;
}
}
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";
return JavaRuntimeLocator.Resolve();
}
private (