Fix: Blockiere System.exit() mit SecurityManager statt s9api
Problem: s9api Klassen nicht im Classpath verfügbar (NoClassDefFoundError) Root Cause: Saxon's Transform.main() ruft System.exit() auf Lösung: Custom SecurityManager der System.exit() blockiert - NoExitSecurityManager: checkExit() wirft SecurityException - Fängt SecurityException ab wenn Saxon System.exit() versucht - Extrahiert Fehlermeldung aus Saxon's stderr - Worker bleibt am Leben und kann weitere Jobs verarbeiten Dieser Ansatz funktioniert mit jeder Saxon-Version ohne s9api-Abhängigkeiten. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
+81
-50
@@ -17,20 +17,33 @@ 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.s9api.*;
|
import net.sf.saxon.Transform;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
|
||||||
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;
|
||||||
|
|
||||||
// Create Saxon Processor (reusable)
|
System.err.println("SaxonWorker started and ready (System.exit blocked)");
|
||||||
Processor processor = new Processor(false);
|
|
||||||
|
|
||||||
System.err.println("SaxonWorker started and ready (using s9api)");
|
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -62,67 +75,85 @@ public class SaxonWorker {
|
|||||||
String xslStylesheet = parts[1];
|
String xslStylesheet = parts[1];
|
||||||
String outputFo = parts[2];
|
String outputFo = parts[2];
|
||||||
|
|
||||||
System.err.println("DEBUG: Files - XML: " + sourceXml);
|
System.err.println("DEBUG: Building Saxon args...");
|
||||||
System.err.println("DEBUG: Files - XSL: " + xslStylesheet);
|
|
||||||
System.err.println("DEBUG: Files - OUT: " + outputFo);
|
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
|
|
||||||
// Parse parameters if present
|
// Build Saxon arguments
|
||||||
Map<String, String> xsltParams = new HashMap<>();
|
List<String> saxonArgs = new ArrayList<>();
|
||||||
|
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() && param.contains("=")) {
|
if (!param.isEmpty()) {
|
||||||
String[] kv = param.split("=", 2);
|
saxonArgs.add(param);
|
||||||
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();
|
||||||
|
|
||||||
System.err.println("DEBUG: Compiling stylesheet...");
|
// Redirect Saxon output to stderr to avoid polluting stdout
|
||||||
System.err.flush();
|
PrintStream oldOut = System.out;
|
||||||
|
PrintStream oldErr = System.err;
|
||||||
|
ByteArrayOutputStream saxonOut = new ByteArrayOutputStream();
|
||||||
|
ByteArrayOutputStream saxonErr = new ByteArrayOutputStream();
|
||||||
|
|
||||||
// Compile stylesheet (s9api)
|
try {
|
||||||
XsltCompiler compiler = processor.newXsltCompiler();
|
System.setOut(new PrintStream(saxonOut));
|
||||||
XsltExecutable executable = compiler.compile(new StreamSource(new File(xslStylesheet)));
|
System.setErr(new PrintStream(saxonErr));
|
||||||
|
|
||||||
System.err.println("DEBUG: Creating transformer...");
|
// Run Saxon transformation
|
||||||
System.err.flush();
|
// If Saxon calls System.exit(), our SecurityManager will throw SecurityException
|
||||||
|
Transform.main(saxonArgs.toArray(new String[0]));
|
||||||
|
|
||||||
// Create transformer
|
// Restore streams
|
||||||
Xslt30Transformer transformer = executable.load30();
|
System.setOut(oldOut);
|
||||||
|
System.setErr(oldErr);
|
||||||
|
|
||||||
// Set parameters
|
oldErr.println("DEBUG: Saxon transformation completed");
|
||||||
if (!xsltParams.isEmpty()) {
|
oldErr.flush();
|
||||||
Map<QName, XdmValue> params = new HashMap<>();
|
|
||||||
for (Map.Entry<String, String> param : xsltParams.entrySet()) {
|
// Send success response
|
||||||
params.put(new QName(param.getKey()), XdmValue.makeValue(param.getValue()));
|
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) + "...";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
transformer.setStylesheetParameters(params);
|
|
||||||
|
System.out.println("ERROR: " + errorMsg);
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
System.out.println("OK");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
} catch (SaxonApiException e) {
|
|
||||||
System.err.println("DEBUG: Saxon API exception: " + e.getClass().getName());
|
|
||||||
System.err.flush();
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
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();
|
||||||
|
|||||||
Reference in New Issue
Block a user