Fix: Verwende Saxon s9api statt Transform.main() um System.exit() zu vermeiden

Problem: Transform.main() ruft System.exit() auf, was den gesamten Worker-Prozess beendet

Lösung: Umstellung auf Saxon s9api (programmatische API):
- Verwendet Processor, XsltCompiler, XsltExecutable, Xslt30Transformer
- Wirft SaxonApiException statt System.exit() aufzurufen
- Processor wird einmalig erstellt und wiederverwendet (Performance!)
- Parameter-Handling mit QName und XdmValue
- Serializer für Ausgabe statt Kommandozeilen-Args

Dies sollte die Worker-Crashes vollständig beheben.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 15:50:03 +01:00
parent 8b29214abd
commit 6fcf706d96
+46 -37
View File
@@ -17,7 +17,8 @@ logger = logging.getLogger(__name__)
# Java-Worker-Code (wird zur Laufzeit kompiliert) # Java-Worker-Code (wird zur Laufzeit kompiliert)
SAXON_WORKER_JAVA = """ SAXON_WORKER_JAVA = """
import net.sf.saxon.Transform; import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@@ -26,7 +27,10 @@ public class SaxonWorker {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line; String line;
System.err.println("SaxonWorker started and ready"); // Create Saxon Processor (reusable)
Processor processor = new Processor(false);
System.err.println("SaxonWorker started and ready (using s9api)");
System.err.flush(); System.err.flush();
try { try {
@@ -58,62 +62,67 @@ public class SaxonWorker {
String xslStylesheet = parts[1]; String xslStylesheet = parts[1];
String outputFo = parts[2]; String outputFo = parts[2];
System.err.println("DEBUG: Building Saxon args..."); System.err.println("DEBUG: Files - XML: " + sourceXml);
System.err.println("DEBUG: Files - XSL: " + xslStylesheet);
System.err.println("DEBUG: Files - OUT: " + outputFo);
System.err.flush(); System.err.flush();
// Build Saxon arguments // Parse parameters if present
List<String> saxonArgs = new ArrayList<>(); Map<String, String> xsltParams = new HashMap<>();
saxonArgs.add("-s:" + sourceXml);
saxonArgs.add("-xsl:" + xslStylesheet);
saxonArgs.add("-o:" + outputFo);
// Add parameters if present
if (parts.length > 3 && !parts[3].isEmpty()) { if (parts.length > 3 && !parts[3].isEmpty()) {
String[] params = parts[3].split("\\\\|\\\\|\\\\|"); String[] params = parts[3].split("\\\\|\\\\|\\\\|");
for (String param : params) { for (String param : params) {
if (!param.isEmpty()) { if (!param.isEmpty() && param.contains("=")) {
saxonArgs.add(param); String[] kv = param.split("=", 2);
xsltParams.put(kv[0], kv[1]);
} }
} }
} }
System.err.println("DEBUG: Parameters: " + xsltParams.size());
System.err.println("DEBUG: Running Saxon transformation...");
System.err.flush(); System.err.flush();
// Redirect Saxon output to stderr to avoid polluting stdout System.err.println("DEBUG: Compiling stylesheet...");
PrintStream oldOut = System.out; System.err.flush();
PrintStream oldErr = System.err;
ByteArrayOutputStream saxonOut = new ByteArrayOutputStream();
ByteArrayOutputStream saxonErr = new ByteArrayOutputStream();
try { // Compile stylesheet (s9api)
System.setOut(new PrintStream(saxonOut)); XsltCompiler compiler = processor.newXsltCompiler();
System.setErr(new PrintStream(saxonErr)); XsltExecutable executable = compiler.compile(new StreamSource(new File(xslStylesheet)));
// Run Saxon transformation System.err.println("DEBUG: Creating transformer...");
Transform.main(saxonArgs.toArray(new String[0])); System.err.flush();
// Restore streams // Create transformer
System.setOut(oldOut); Xslt30Transformer transformer = executable.load30();
System.setErr(oldErr);
oldErr.println("DEBUG: Saxon transformation completed"); // Set parameters
oldErr.flush(); if (!xsltParams.isEmpty()) {
Map<QName, XdmValue> params = new HashMap<>();
for (Map.Entry<String, String> param : xsltParams.entrySet()) {
params.put(new QName(param.getKey()), XdmValue.makeValue(param.getValue()));
}
transformer.setStylesheetParameters(params);
}
System.err.println("DEBUG: Running transformation...");
System.err.flush();
// Run transformation
Serializer serializer = processor.newSerializer(new File(outputFo));
transformer.transform(new StreamSource(new File(sourceXml)), serializer);
System.err.println("DEBUG: Transformation completed successfully");
System.err.flush();
// Send success response // Send success response
System.out.println("OK"); System.out.println("OK");
System.out.flush(); System.out.flush();
} catch (Exception e) { } catch (SaxonApiException e) {
System.setOut(oldOut); System.err.println("DEBUG: Saxon API exception: " + e.getClass().getName());
System.setErr(oldErr); System.err.flush();
oldErr.println("DEBUG: Saxon exception: " + e.getClass().getName()); e.printStackTrace(System.err);
oldErr.flush();
e.printStackTrace(oldErr);
System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName())); System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName()));
System.out.flush(); System.out.flush();
}
} catch (Exception e) { } catch (Exception e) {
System.err.println("DEBUG: Job processing exception: " + e.getClass().getName()); System.err.println("DEBUG: Job processing exception: " + e.getClass().getName());
System.err.flush(); System.err.flush();