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:
+57
-73
@@ -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,85 +62,82 @@ 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<String> 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();
|
||||
// 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");
|
||||
}
|
||||
|
||||
try {
|
||||
System.setOut(new PrintStream(saxonOut));
|
||||
System.setErr(new PrintStream(saxonErr));
|
||||
@Override
|
||||
public void error(TransformerException e) {
|
||||
errors.append("ERROR: ").append(e.getMessage()).append("\\n");
|
||||
}
|
||||
|
||||
// Run Saxon transformation
|
||||
// If Saxon calls System.exit(), our SecurityManager will throw SecurityException
|
||||
Transform.main(saxonArgs.toArray(new String[0]));
|
||||
@Override
|
||||
public void fatalError(TransformerException e) throws TransformerException {
|
||||
errors.append("FATAL: ").append(e.getMessage()).append("\\n");
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore streams
|
||||
System.setOut(oldOut);
|
||||
System.setErr(oldErr);
|
||||
// Run transformation
|
||||
transformer.transform(xmlSource, result);
|
||||
|
||||
oldErr.println("DEBUG: Saxon transformation completed");
|
||||
oldErr.flush();
|
||||
System.err.println("DEBUG: Transformation completed");
|
||||
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.flush();
|
||||
|
||||
} catch (SecurityException e) {
|
||||
// System.exit() was called by Saxon - treat as error
|
||||
System.setOut(oldOut);
|
||||
System.setErr(oldErr);
|
||||
} catch (TransformerException e) {
|
||||
System.err.println("DEBUG: Transformer exception: " + e.getClass().getName());
|
||||
System.err.flush();
|
||||
e.printStackTrace(System.err);
|
||||
|
||||
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) + "...";
|
||||
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.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) {
|
||||
System.err.println("DEBUG: Job processing exception: " + e.getClass().getName());
|
||||
System.err.flush();
|
||||
|
||||
Reference in New Issue
Block a user