diff --git a/ZA.CoreService.ESBCertificateManager/Form1.cs b/ZA.CoreService.ESBCertificateManager/Form1.cs index 4a96ce5..a588088 100644 --- a/ZA.CoreService.ESBCertificateManager/Form1.cs +++ b/ZA.CoreService.ESBCertificateManager/Form1.cs @@ -172,13 +172,12 @@ namespace ZA.CoreService.ESBCertificateManager coordinator, isSettingsMode: true); - if (settingsForm.ShowDialog(this) != DialogResult.OK) - { - return; - } + // Nach dem Schließen immer neu laden: + // Pfade/Container können auch ohne „Profil übernehmen“ angelegt worden sein. + _ = settingsForm.ShowDialog(this); SetStatus( - "Einstellungen übernommen. Anwendung wird aktualisiert ...", + "Einstellungen geschlossen. Ziele werden aktualisiert ...", isError: false); await InitializeApplicationAsync(); @@ -1938,6 +1937,24 @@ namespace ZA.CoreService.ESBCertificateManager { UpdateToNextStep(4); } + else + { + string details = string.Join( + Environment.NewLine + Environment.NewLine, + runResult.TargetResults + .Where(result => !result.Success) + .Select(result => + $"{result.TargetName}: {result.StatusText}" + + Environment.NewLine + + (result.Detail ?? string.Empty))); + + CopyableErrorDialog.Show( + this, + "Neustart fehlgeschlagen (MfApi)", + string.IsNullOrWhiteSpace(details) + ? "Neustart fehlgeschlagen (keine Details)." + : details); + } } catch (OperationCanceledException) { @@ -1946,7 +1963,10 @@ namespace ZA.CoreService.ESBCertificateManager catch (Exception ex) { SetStatus($"Neustart fehlgeschlagen: {ex.Message}", isError: true); - MessageBox.Show(this, ex.Message, "ESB neu starten", MessageBoxButtons.OK, MessageBoxIcon.Error); + CopyableErrorDialog.Show( + this, + "Neustart fehlgeschlagen (MfApi)", + ex.ToString()); } finally { @@ -2051,6 +2071,20 @@ namespace ZA.CoreService.ESBCertificateManager SetStatus( "Deployment für mindestens ein Ziel fehlgeschlagen.", isError: true); + + string details = string.Join( + Environment.NewLine + Environment.NewLine, + runResult.TargetResults + .Where(result => !result.Success) + .Select(result => + $"{result.TargetName}: {result.StatusText}" + + Environment.NewLine + + (result.Detail ?? string.Empty))); + + CopyableErrorDialog.Show( + this, + "Deployment fehlgeschlagen", + details); } } catch (OperationCanceledException) @@ -2063,12 +2097,10 @@ namespace ZA.CoreService.ESBCertificateManager $"Deployment fehlgeschlagen: {ex.Message}", isError: true); - MessageBox.Show( + CopyableErrorDialog.Show( this, - ex.Message, "Deployment fehlgeschlagen", - MessageBoxButtons.OK, - MessageBoxIcon.Error); + ex.ToString()); } finally { diff --git a/ZA.CoreService.ESBCertificateManager/Models/AppSettings.cs b/ZA.CoreService.ESBCertificateManager/Models/AppSettings.cs index 416ab06..97ae614 100644 --- a/ZA.CoreService.ESBCertificateManager/Models/AppSettings.cs +++ b/ZA.CoreService.ESBCertificateManager/Models/AppSettings.cs @@ -46,7 +46,7 @@ public sealed class DatabaseSettings public sealed class RuntimeSettings { public string JavaExecutablePath { get; set; } = - @"Runtime\bin\java.exe"; + @"C:\Program Files (x86)\Java\jre1.8.0_481\bin\java.exe"; public string SonicClientLibraryPath { get; set; } = @"Runtime\SonicClient\lib"; diff --git a/ZA.CoreService.ESBCertificateManager/Models/DatabaseSonicConnection.cs b/ZA.CoreService.ESBCertificateManager/Models/DatabaseSonicConnection.cs index b7fdbd8..1482a8e 100644 --- a/ZA.CoreService.ESBCertificateManager/Models/DatabaseSonicConnection.cs +++ b/ZA.CoreService.ESBCertificateManager/Models/DatabaseSonicConnection.cs @@ -72,10 +72,18 @@ public sealed class DatabaseSonicConnection "Bitte die Einstellungen öffnen und ein Benutzerprofil hinterlegen."); } - string javaExecutablePath = - PathResolver.ResolvePath( + string? javaExecutablePath = + JavaRuntimeLocator.Resolve( runtimeSettings.JavaExecutablePath); + if (javaExecutablePath is null) + { + throw new InvalidOperationException( + "Java 8 wurde nicht gefunden. " + + "Bitte Runtime:JavaExecutablePath auf " + + @"jre1.8*\bin\java.exe setzen."); + } + string sonicClientLibraryPath = PathResolver.ResolvePath( runtimeSettings.SonicClientLibraryPath); diff --git a/ZA.CoreService.ESBCertificateManager/Services/CopyableErrorDialog.cs b/ZA.CoreService.ESBCertificateManager/Services/CopyableErrorDialog.cs new file mode 100644 index 0000000..6227fd3 --- /dev/null +++ b/ZA.CoreService.ESBCertificateManager/Services/CopyableErrorDialog.cs @@ -0,0 +1,135 @@ +namespace ZA.CoreService.ESBCertificateManager.Services; + +/// +/// Fehlerdialog mit Text und Button „In Zwischenablage kopieren“. +/// Kopiert den Fehlertext beim Öffnen automatisch. +/// +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; + } + } +} diff --git a/ZA.CoreService.ESBCertificateManager/Services/JavaRuntimeLocator.cs b/ZA.CoreService.ESBCertificateManager/Services/JavaRuntimeLocator.cs new file mode 100644 index 0000000..1352b63 --- /dev/null +++ b/ZA.CoreService.ESBCertificateManager/Services/JavaRuntimeLocator.cs @@ -0,0 +1,121 @@ +namespace ZA.CoreService.ESBCertificateManager.Services; + +/// +/// Findet eine nutzbare Java-8-Runtime für Sonic MfApi. +/// +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 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; + } + } +} diff --git a/ZA.CoreService.ESBCertificateManager/Services/RestartExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/RestartExecutor.cs index 41e9297..00b0896 100644 --- a/ZA.CoreService.ESBCertificateManager/Services/RestartExecutor.cs +++ b/ZA.CoreService.ESBCertificateManager/Services/RestartExecutor.cs @@ -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 = diff --git a/ZA.CoreService.ESBCertificateManager/Services/RuntimeEnviromentValidator.cs b/ZA.CoreService.ESBCertificateManager/Services/RuntimeEnviromentValidator.cs index 767d781..a65c355 100644 --- a/ZA.CoreService.ESBCertificateManager/Services/RuntimeEnviromentValidator.cs +++ b/ZA.CoreService.ESBCertificateManager/Services/RuntimeEnviromentValidator.cs @@ -11,8 +11,8 @@ public sealed class RuntimeEnvironmentValidator { List 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 diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicCredentialTester.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicCredentialTester.cs index 7b5606d..583fca4 100644 --- a/ZA.CoreService.ESBCertificateManager/Services/SonicCredentialTester.cs +++ b/ZA.CoreService.ESBCertificateManager/Services/SonicCredentialTester.cs @@ -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)) diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs index 2fa318a..d445da6 100644 --- a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs +++ b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs @@ -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 - 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 ( diff --git a/ZA.CoreService.ESBCertificateManager/Setup/SetupWizardForm.cs b/ZA.CoreService.ESBCertificateManager/Setup/SetupWizardForm.cs index ccc3aa1..4fdff3a 100644 --- a/ZA.CoreService.ESBCertificateManager/Setup/SetupWizardForm.cs +++ b/ZA.CoreService.ESBCertificateManager/Setup/SetupWizardForm.cs @@ -67,6 +67,15 @@ public sealed class SetupWizardForm : Form ShowPanel(_panelStatus, _navButtons[0]); Shown += async (_, _) => await RefreshAllAsync(); + + FormClosing += (_, e) => + { + // X-Button: in Einstellungen trotzdem als „geschlossen mit Änderungen möglich“ + if (_isSettingsMode && DialogResult == DialogResult.None) + { + DialogResult = DialogResult.OK; + } + }; } private void BuildShell() @@ -1138,10 +1147,10 @@ public sealed class SetupWizardForm : Form { if (_isSettingsMode) { - SetupCheckResult check = await _coordinator.CheckAsync(); - DialogResult = check.IsReady - ? DialogResult.OK - : DialogResult.Cancel; + // Katalog-Änderungen (Pfade/Container) sollen die Hauptansicht + // immer aktualisieren – unabhängig davon, ob das Profil schon „ready“ ist. + _ = await _coordinator.CheckAsync(); + DialogResult = DialogResult.OK; } else { diff --git a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool$Args.class index 729a334..b205b3a 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 59a4fa6..5e969e7 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.jar b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.jar index e944331..86beb9f 100644 Binary files a/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.jar and b/ZA.CoreService.ESBCertificateManager/Tools/SonicMfContainerTool.jar differ diff --git a/ZA.CoreService.ESBCertificateManager/appsettings.json b/ZA.CoreService.ESBCertificateManager/appsettings.json index ea9755d..ae23177 100644 --- a/ZA.CoreService.ESBCertificateManager/appsettings.json +++ b/ZA.CoreService.ESBCertificateManager/appsettings.json @@ -6,7 +6,7 @@ "ConnectionString": "Server=VWEBDEV01;Database=EsbZertifikatManager;Integrated Security=True;Encrypt=True;Column Encryption Setting=Enabled;Application Name=ZA.CoreService.ESBCertificateManager;TrustServerCertificate=True;" }, "Runtime": { - "JavaExecutablePath": "Runtime\\bin\\java.exe", + "JavaExecutablePath": "C:\\Program Files (x86)\\Java\\jre1.8.0_481\\bin\\java.exe", "SonicClientLibraryPath": "Runtime\\SonicClient\\lib", "SetupCompleted": true },