Fix: Verwende JAXP Transformer API statt Transform.main() oder SecurityManager

Problem:
- SecurityManager ist in Java 17+ deprecated und funktioniert nicht mehr
- Transform.main() ruft System.exit() auf und killt Worker
- s9api nicht im Classpath verfügbar

Lösung: JAXP Transformer API (javax.xml.transform)
- Standard Java API, immer verfügbar
- Von Saxon implementiert (registriert sich als TransformerFactory)
- Ruft NIE System.exit() auf
- Wirft TransformerException bei Fehlern
- ErrorListener für saubere Fehlererfassung
- TransformerFactory einmalig erstellt, wiederverwendet (Performance!)

Dies ist die korrekte, robuste Lösung für dieses Problem.

🤖 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 16:15:39 +01:00
parent 40b778b41b
commit 60f4b7dcef
+57 -73
View File
@@ -17,33 +17,20 @@ 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 javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
public class SaxonWorker { public class SaxonWorker {
// Custom SecurityManager to block System.exit()
static class NoExitSecurityManager extends SecurityManager {
@Override
public void checkPermission(java.security.Permission perm) {
// Allow everything
}
@Override
public void checkExit(int status) {
// Block System.exit() by throwing an exception
throw new SecurityException("System.exit() blocked by SaxonWorker");
}
}
public static void main(String[] args) { public static void main(String[] args) {
// Install SecurityManager to prevent System.exit()
System.setSecurityManager(new NoExitSecurityManager());
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 (System.exit blocked)"); // Create TransformerFactory once and reuse
TransformerFactory factory = TransformerFactory.newInstance();
System.err.println("SaxonWorker started and ready (using JAXP Transformer API)");
System.err.flush(); System.err.flush();
try { try {
@@ -75,85 +62,82 @@ 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: Creating transformer from stylesheet...");
System.err.flush(); System.err.flush();
// Build Saxon arguments // Create Source and Result objects
List<String> saxonArgs = new ArrayList<>(); StreamSource xslSource = new StreamSource(new File(xslStylesheet));
saxonArgs.add("-s:" + sourceXml); StreamSource xmlSource = new StreamSource(new File(sourceXml));
saxonArgs.add("-xsl:" + xslStylesheet); StreamResult result = new StreamResult(new File(outputFo));
saxonArgs.add("-o:" + outputFo);
// Add parameters if present System.err.println("DEBUG: Compiling stylesheet...");
System.err.flush();
// Create transformer from stylesheet
Transformer transformer = factory.newTransformer(xslSource);
// Set 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);
transformer.setParameter(kv[0], kv[1]);
System.err.println("DEBUG: Set parameter: " + kv[0] + " = " + kv[1]);
} }
} }
System.err.flush();
} }
System.err.println("DEBUG: Running Saxon transformation..."); System.err.println("DEBUG: Running transformation...");
System.err.flush(); System.err.flush();
// Redirect Saxon output to stderr to avoid polluting stdout // Capture errors via ErrorListener
PrintStream oldOut = System.out; final StringBuilder errors = new StringBuilder();
PrintStream oldErr = System.err; transformer.setErrorListener(new ErrorListener() {
ByteArrayOutputStream saxonOut = new ByteArrayOutputStream(); @Override
ByteArrayOutputStream saxonErr = new ByteArrayOutputStream(); public void warning(TransformerException e) {
errors.append("WARNING: ").append(e.getMessage()).append("\\n");
}
try { @Override
System.setOut(new PrintStream(saxonOut)); public void error(TransformerException e) {
System.setErr(new PrintStream(saxonErr)); errors.append("ERROR: ").append(e.getMessage()).append("\\n");
}
// Run Saxon transformation @Override
// If Saxon calls System.exit(), our SecurityManager will throw SecurityException public void fatalError(TransformerException e) throws TransformerException {
Transform.main(saxonArgs.toArray(new String[0])); errors.append("FATAL: ").append(e.getMessage()).append("\\n");
throw e;
}
});
// Restore streams // Run transformation
System.setOut(oldOut); transformer.transform(xmlSource, result);
System.setErr(oldErr);
oldErr.println("DEBUG: Saxon transformation completed"); System.err.println("DEBUG: Transformation completed");
oldErr.flush(); System.err.flush();
// Send success response // Check for errors
if (errors.length() > 0) {
System.out.println("ERROR: " + errors.toString().trim());
} else {
System.out.println("OK"); System.out.println("OK");
}
System.out.flush(); System.out.flush();
} catch (SecurityException e) { } catch (TransformerException e) {
// System.exit() was called by Saxon - treat as error System.err.println("DEBUG: Transformer exception: " + e.getClass().getName());
System.setOut(oldOut); System.err.flush();
System.setErr(oldErr); e.printStackTrace(System.err);
oldErr.println("DEBUG: Saxon tried to call System.exit() (blocked)"); String errorMsg = e.getMessage();
oldErr.flush(); if (errorMsg == null || errorMsg.isEmpty()) {
errorMsg = e.getClass().getSimpleName();
// Check Saxon's output for error details
String saxonOutput = saxonErr.toString();
String errorMsg = "Transformation failed";
if (!saxonOutput.isEmpty()) {
errorMsg = saxonOutput.trim();
// Limit error message length
if (errorMsg.length() > 200) {
errorMsg = errorMsg.substring(0, 200) + "...";
} }
}
System.out.println("ERROR: " + errorMsg); System.out.println("ERROR: " + errorMsg);
System.out.flush(); System.out.flush();
} catch (Exception e) {
System.setOut(oldOut);
System.setErr(oldErr);
oldErr.println("DEBUG: Saxon exception: " + e.getClass().getName());
oldErr.flush();
e.printStackTrace(oldErr);
System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName()));
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();