From 60f4b7dcef5fa26fdd119f7134309d2dab272c62 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 28 Dec 2025 16:15:39 +0100 Subject: [PATCH] Fix: Verwende JAXP Transformer API statt Transform.main() oder SecurityManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/saxon_pool.py | 146 +++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 81 deletions(-) diff --git a/src/saxon_pool.py b/src/saxon_pool.py index 49c6a7f..13b93da 100644 --- a/src/saxon_pool.py +++ b/src/saxon_pool.py @@ -17,33 +17,20 @@ logger = logging.getLogger(__name__) # Java-Worker-Code (wird zur Laufzeit kompiliert) SAXON_WORKER_JAVA = """ -import net.sf.saxon.Transform; +import javax.xml.transform.*; +import javax.xml.transform.stream.*; import java.io.*; import java.util.*; 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) { - // Install SecurityManager to prevent System.exit() - System.setSecurityManager(new NoExitSecurityManager()); - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 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(); try { @@ -75,84 +62,81 @@ public class SaxonWorker { String xslStylesheet = parts[1]; String outputFo = parts[2]; - System.err.println("DEBUG: Building Saxon args..."); + System.err.println("DEBUG: Creating transformer from stylesheet..."); System.err.flush(); - // Build Saxon arguments - List saxonArgs = new ArrayList<>(); - saxonArgs.add("-s:" + sourceXml); - saxonArgs.add("-xsl:" + xslStylesheet); - saxonArgs.add("-o:" + outputFo); + // Create Source and Result objects + StreamSource xslSource = new StreamSource(new File(xslStylesheet)); + StreamSource xmlSource = new StreamSource(new File(sourceXml)); + StreamResult result = new StreamResult(new File(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()) { String[] params = parts[3].split("\\\\|\\\\|\\\\|"); for (String param : params) { - if (!param.isEmpty()) { - saxonArgs.add(param); + if (!param.isEmpty() && param.contains("=")) { + 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(); - // Redirect Saxon output to stderr to avoid polluting stdout - PrintStream oldOut = System.out; - PrintStream oldErr = System.err; - ByteArrayOutputStream saxonOut = new ByteArrayOutputStream(); - ByteArrayOutputStream saxonErr = new ByteArrayOutputStream(); - - try { - System.setOut(new PrintStream(saxonOut)); - System.setErr(new PrintStream(saxonErr)); - - // Run Saxon transformation - // If Saxon calls System.exit(), our SecurityManager will throw SecurityException - Transform.main(saxonArgs.toArray(new String[0])); - - // Restore streams - System.setOut(oldOut); - System.setErr(oldErr); - - oldErr.println("DEBUG: Saxon transformation completed"); - oldErr.flush(); - - // Send success response - System.out.println("OK"); - System.out.flush(); - - } catch (SecurityException e) { - // System.exit() was called by Saxon - treat as error - System.setOut(oldOut); - System.setErr(oldErr); - - oldErr.println("DEBUG: Saxon tried to call System.exit() (blocked)"); - oldErr.flush(); - - // 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) + "..."; - } + // Capture errors via ErrorListener + final StringBuilder errors = new StringBuilder(); + transformer.setErrorListener(new ErrorListener() { + @Override + public void warning(TransformerException e) { + errors.append("WARNING: ").append(e.getMessage()).append("\\n"); } - System.out.println("ERROR: " + errorMsg); - System.out.flush(); + @Override + public void error(TransformerException e) { + errors.append("ERROR: ").append(e.getMessage()).append("\\n"); + } - } 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(); + @Override + public void fatalError(TransformerException e) throws TransformerException { + errors.append("FATAL: ").append(e.getMessage()).append("\\n"); + throw e; + } + }); + + // Run transformation + transformer.transform(xmlSource, result); + + System.err.println("DEBUG: Transformation completed"); + System.err.flush(); + + // Check for errors + if (errors.length() > 0) { + System.out.println("ERROR: " + errors.toString().trim()); + } else { + System.out.println("OK"); } + System.out.flush(); + + } catch (TransformerException e) { + System.err.println("DEBUG: Transformer exception: " + e.getClass().getName()); + System.err.flush(); + e.printStackTrace(System.err); + + String errorMsg = e.getMessage(); + if (errorMsg == null || errorMsg.isEmpty()) { + errorMsg = e.getClass().getSimpleName(); + } + System.out.println("ERROR: " + errorMsg); + System.out.flush(); } catch (Exception e) { System.err.println("DEBUG: Job processing exception: " + e.getClass().getName());