diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs index 8a711f8..a70db52 100644 --- a/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs +++ b/ZA.CoreService.ESBCertificateManager/Services/SonicMfApiExecutor.cs @@ -178,8 +178,28 @@ public sealed class SonicMfApiExecutor 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}"); + } + } + if (javaExe is null) { string sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome) @@ -188,20 +208,22 @@ public sealed class SonicMfApiExecutor string checkedList = javaResult.CheckedPaths.Count == 0 ? "(keine Kandidaten gesammelt)" : string.Join("\n - ", javaResult.CheckedPaths.Take(MaxCheckedPathsInError)); - if (javaResult.CheckedPaths.Count > MaxCheckedPathsInError) - { - checkedList += $"\n - … (+{javaResult.CheckedPaths.Count - MaxCheckedPathsInError} weitere)"; - } return (false, null, null, null, "Java nicht gefunden.\n" + $"Verwendetes SonicHome: '{sonicHome}'\n" + - $"SonicHome existiert: {(Directory.Exists(sonicHome) ? "ja" : "nein")}\n" + - "Konfiguration: SonicConnection.JavaHome / JavaPath, sonst Auto-Suche " + - "(JAVA_HOME/JRE_HOME, setenv.bat, rekursiv unter SonicHome, MQ/ESB-Nachbarn, Registry, where).\n" + - "Geprüfte Pfade:\n - " + checkedList + "\n" + - "Tipp: JavaHome oder JavaPath in appsettings auf die echte java.exe setzen " + - "(z.B. C:\\Sonic\\MQ10.0\\jre\\bin\\java.exe)."); + "Konfiguration: JavaPath/JavaHome auf eine Java-8+-Runtime setzen.\n" + + "Geprüfte Pfade:\n - " + checkedList); + } + + 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? libDir, string? libError) = ResolveLibDirectoryDetailed(); @@ -210,9 +232,6 @@ public sealed class SonicMfApiExecutor return (false, null, null, null, libError); } - int runtimeMajor = await GetJavaClassMajorAsync(javaExe, cancellationToken); - // Sonic/SMC nutzt typisch Java 8 (major 52). Nie mit höherer Class-Version starten. - // Vorcompilierte .class/.jar nur nutzen, wenn Class-Version zur Runtime passt. if (TryResolvePrebuiltTool(runtimeMajor, out string? prebuiltDir, out string? prebuiltEntry, out string? prebuiltError) && prebuiltDir is not null && prebuiltEntry is not null) @@ -385,32 +404,119 @@ public sealed class SonicMfApiExecutor using Process p = new() { StartInfo = psi }; if (!p.Start()) { - return 52; // Sonic-Default Java 8 + return 0; } string err = await p.StandardError.ReadToEndAsync(cancellationToken); string output = await p.StandardOutput.ReadToEndAsync(cancellationToken); await p.WaitForExitAsync(cancellationToken); - string text = (err + "\n" + output).ToLowerInvariant(); - - if (text.Contains("version \"1.8") || text.Contains("version \"8")) - { - return 52; - } - - Match m = Regex.Match(text, @"version ""(\d+)"); - if (m.Success && int.TryParse(m.Groups[1].Value, out int major) && major >= 9) - { - // Java 9+ class major = 44 + version => 9→53, 11→55, 17→61, 21→65 - return 44 + major; - } + return ParseJavaVersionToClassMajor(err + "\n" + output); } catch { - // ignore + 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 } - return 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)