summaryrefslogtreecommitdiff
path: root/test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java
diff options
context:
space:
mode:
Diffstat (limited to 'test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java')
-rw-r--r--test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java1013
1 files changed, 1013 insertions, 0 deletions
diff --git a/test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java b/test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java
new file mode 100644
index 0000000..71b078b
--- /dev/null
+++ b/test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java
@@ -0,0 +1,1013 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id$
+ */
+
+/*
+ *
+ * TestMultiTypeThreads.java
+ *
+ */
+package org.apache.qetest.trax;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+//-------------------------------------------------------------------------
+
+/**
+ * Testing multiple simultaneous processors on different threads
+ * using different processing methods with TRAX.
+ * <p>No validation of output files is currently done! You must manually
+ * inspect any logfiles. Most options can be passed in with a Properties file.</p>
+ * <p>Note: Most automated tests extend XSLProcessorTestBase, and
+ * are named *Test.java. Since we are semi-manual, we're
+ * named Test*.java instead.</p>
+ * We assume Features.STREAM.
+ * @author shane_curcuru@lotus.com
+ */
+public class TestMultiTypeThreads
+{
+
+ /**
+ * Convenience method to print out usage information.
+ *
+ * NEEDSDOC ($objectName$) @return
+ */
+ public static String usage()
+ {
+
+ return ("Usage: TestMultiTypeThreads [-load] file.properties :\n"
+ + " where the properties file can set:,\n"
+ + " inputDir=e:\\builds\\xsl-test\n"
+ + " outputDir=e:\\builds\\xsl-test\\results\n"
+ + " logFile=e:\\builds\\xsl-test\\results\\TestMultiTypeThreads.xml\n"
+ + " numRunners=5\n" + " numRunnerCalls=10\n"
+ + " setOneFile=bool01\n" + " setTwoFile=expr01\n"
+ + " setThreeFile=numb01\n" + " paramName=SomeParam\n"
+ + " paramVal=TheValue\n");
+ }
+
+ /** NEEDSDOC Field debug */
+ public boolean debug = true; // for adhoc debugging
+
+ /**
+ * Number of sets of worker threads to create and loops per runner.
+ * <p>'numRunners=xx', default is 10; 'numRunnerCalls=xx', default is 50.</p>
+ */
+ protected int numRunners = 10;
+
+ /**
+ * Number of sets of worker threads to create and loops per runner.
+ * <p>'numRunners=xx', default is 10; 'numRunnerCalls=xx', default is 50.</p>
+ */
+ protected int numRunnerCalls = 50;
+
+ /**
+ * Root input filenames that certain runners should use, in the inputDir.
+ * <p>'setOneFile=File'; 'setTwoFile=File'; 'setThreeFile=File'
+ * in .prop file to set; default is TestMultiTypeThreads1, TestMultiTypeThreads2, TestMultiTypeThreads3.</p>
+ * <p>Files are found in 'inputDir=c:\bar\baz' from .prop file.</p>
+ */
+ protected String inputDir = null;
+
+ /** NEEDSDOC Field setOneFilenameRoot */
+ protected String setOneFilenameRoot = "TestMultiTypeThreads1";
+
+ /** NEEDSDOC Field setTwoFilenameRoot */
+ protected String setTwoFilenameRoot = "TestMultiTypeThreads2";
+
+ /** NEEDSDOC Field setThreeFilenameRoot */
+ protected String setThreeFilenameRoot = "TestMultiTypeThreads3";
+
+ /**
+ * All output logs and files get put in the outputDir.
+ */
+ protected String outputDir = null;
+
+ /**
+ * Sample PARAM name that certain runners should use.
+ * <p>Use 'paramName=xx' in .prop file to set, default is test1.</p>
+ */
+ protected String paramName = "test1";
+
+ /**
+ * Sample PARAM value that certain runners should use.
+ * <p>Use 'paramVal=xx' in .prop file to set, default is bar.</p>
+ */
+ protected String paramVal = "bar";
+
+ /**
+ * liaisonClassName that just the *second* set of runners should use.
+ * <p>Use 'liaison=xx' in .prop file to set, default is null (whatever the processor's default is).</p>
+ */
+ protected String liaison = null; // TRAX unused
+
+ // Used to pass info to runners; simpler to update than changing ctors
+
+ /** RunnerID offset in ctor's array initializer. */
+ public static final int ID = 0;
+
+ /** NEEDSDOC Field XMLNAME */
+ public static final int XMLNAME = 1;
+
+ /** NEEDSDOC Field XSLNAME */
+ public static final int XSLNAME = 2;
+
+ /** NEEDSDOC Field OUTNAME */
+ public static final int OUTNAME = 3;
+
+ /** NEEDSDOC Field PARAMNAME */
+ public static final int PARAMNAME = 4;
+
+ /** NEEDSDOC Field PARAMVAL */
+ public static final int PARAMVAL = 5;
+
+ /** NEEDSDOC Field OPTIONS */
+ public static final int OPTIONS = 6;
+
+ /** NEEDSDOC Field LIAISON */
+ public static final int LIAISON = 7;
+
+ /** TRANSFORM_TYPE defines which 'type' - dom, sax, streams, etc. */
+ public static final int TRANSFORM_TYPE = 8;
+
+ /** NEEDSDOC Field FUTUREUSE */
+ public static final int FUTUREUSE = 9;
+
+ /**
+ * Name of main file's output logging; each runner also has separate output.
+ */
+ protected String logFileName = "TestMultiTypeThreads.xml";
+
+ /**
+ * Construct multiple threads with processors and run them all.
+ * @author Shane Curcuru & Scott Boag
+ * <p>Preprocesses some stylesheets, then creates lots of worker threads.</p>
+ */
+ public void runTest()
+ {
+
+ // Prepare a log file and dump out some basic info
+ createLogFile(logFileName);
+ println("<?xml version=\"1.0\"?>");
+ println("<resultsfile logFile=\"" + logFileName + "\">");
+ println("<message desc=\"threads=" + (3 * numRunners)
+ + " iterations=" + numRunnerCalls + "\"/>");
+ println("<message desc=\"oneF=" + setOneFilenameRoot + " twof="
+ + setTwoFilenameRoot + " threef=" + setThreeFilenameRoot
+ + "\"/>");
+ println("<message desc=\"param=" + paramName + " val=" + paramVal
+ + " liaison=" + liaison + "\"/>");
+
+ // Preprocess some stylesheets for use by the runners
+ String errStr = "Create processor threw: ";
+ Templates stylesheet1, stylesheet2, stylesheet3;
+
+ try
+ {
+ String setOneURL = filenameToURI(inputDir + setOneFilenameRoot + ".xsl");
+ String setTwoURL = filenameToURI(inputDir + setTwoFilenameRoot + ".xsl");
+ String setThreeURL = filenameToURI(inputDir + setThreeFilenameRoot + ".xsl");
+
+ TransformerFactory factory = TransformerFactory.newInstance();
+
+ // Note: for now, just use StreamSources to build all stylesheets
+ errStr = "Processing stylesheet1 threw: ";
+ stylesheet1 =
+ factory.newTemplates(new StreamSource(setOneURL));
+ errStr = "Processing stylesheet2 threw: ";
+ stylesheet2 =
+ factory.newTemplates(new StreamSource(setTwoURL));
+ errStr = "Processing stylesheet3 threw: ";
+ stylesheet3 =
+ factory.newTemplates(new StreamSource(setThreeURL));
+ }
+ catch (Exception e)
+ {
+ println("<arbitrary desc=\"" + errStr + e.toString() + "\">");
+
+ if (pWriter != null)
+ {
+ e.printStackTrace(pWriter);
+ }
+
+ e.printStackTrace();
+ println("</arbitrary>");
+
+ return;
+ }
+
+ errStr = "PreCreating runners threw: ";
+
+ try
+ {
+ String[] rValues = new String[FUTUREUSE];
+
+ // Create a whole bunch of worker threads and run them
+ for (int i = 0; i < numRunners; i++)
+ {
+ TMTThreadsRunner r1, r2, r3;
+ Thread t1, t2, t3;
+ String transformType = StreamSource.FEATURE;
+
+ // Alternate sets of runners use alternate transform types
+ if ((i % 3) == 2)
+ {
+ transformType = DOMSource.FEATURE;
+ }
+ else if ((i % 3) == 1)
+ {
+ transformType = StreamSource.FEATURE;
+ }
+ else
+ {
+ transformType = SAXSource.FEATURE;
+ }
+ // First set of runners reports on memory usage periodically
+ rValues[ID] = "one-" + i;
+ rValues[XMLNAME] = filenameToURI(inputDir + setOneFilenameRoot + ".xml");
+ rValues[XSLNAME] = filenameToURI(inputDir + setOneFilenameRoot + ".xsl");
+ rValues[OUTNAME] = outputDir + setOneFilenameRoot + "r" + i;
+ rValues[PARAMNAME] = paramName;
+ rValues[PARAMVAL] = paramVal;
+ rValues[OPTIONS] = "memory;param";
+ rValues[TRANSFORM_TYPE] = transformType;
+ errStr = "Creating runnerone-" + i + " threw: ";
+ r1 = new TMTThreadsRunner(rValues, stylesheet1,
+ numRunnerCalls);
+ t1 = new Thread(r1);
+
+ t1.start();
+
+ // Second set of runners is polite; uses optional liaison
+ rValues[ID] = "two-" + i;
+ rValues[XMLNAME] = filenameToURI(inputDir + setTwoFilenameRoot + ".xml");
+ rValues[XSLNAME] = filenameToURI(inputDir + setTwoFilenameRoot + ".xsl");
+ rValues[OUTNAME] = outputDir + setTwoFilenameRoot + "r" + i;
+ rValues[PARAMNAME] = paramName;
+ rValues[PARAMVAL] = paramVal;
+ rValues[OPTIONS] = "polite;param";
+ rValues[TRANSFORM_TYPE] = transformType;
+
+ if ((liaison != null) &&!(liaison.equals("")))
+ rValues[LIAISON] = liaison;
+
+ errStr = "Creating runnertwo-" + i + " threw: ";
+ r2 = new TMTThreadsRunner(rValues, stylesheet2,
+ numRunnerCalls);
+ t2 = new Thread(r2);
+
+ t2.start();
+
+ rValues[LIAISON] = null;
+
+ // Third set of runners will recreate it's processor each time
+ // and report memory usage; but not set the param
+ // Note: this causes lots of calls to System.gc
+ rValues[ID] = "thr-" + i;
+ rValues[XMLNAME] = filenameToURI(inputDir + setThreeFilenameRoot + ".xml");
+ rValues[XSLNAME] = filenameToURI(inputDir + setThreeFilenameRoot + ".xsl");
+ rValues[OUTNAME] = outputDir + setThreeFilenameRoot + "r" + i;
+ rValues[PARAMNAME] = paramName;
+ rValues[PARAMVAL] = paramVal;
+ rValues[OPTIONS] = "recreate;memory";
+ rValues[TRANSFORM_TYPE] = transformType;
+ errStr = "Creating runnerthree-" + i + " threw: ";
+ r3 = new TMTThreadsRunner(rValues, stylesheet3,
+ numRunnerCalls);
+ t3 = new Thread(r3);
+
+ t3.start();
+ println("<message desc=\"Created " + i
+ + "th set of runners.\"/>");
+ }
+ }
+ catch (Exception e)
+ {
+ println("<arbitrary desc=\"" + errStr + e.toString() + "\">");
+
+ if (pWriter != null)
+ {
+ e.printStackTrace(pWriter);
+ }
+
+ e.printStackTrace();
+ println("</arbitrary>");
+ }
+
+ // Clean up our own references, just for completeness
+ stylesheet1 = null;
+ stylesheet2 = null;
+ stylesheet3 = null;
+ errStr = null;
+
+ println("<message desc=\"Created all our runners!\"/>");
+ println("<message desc=\"TestMultiTypeThreads main thread now complete\"/>");
+ println("</resultsfile>");
+
+ if (pWriter != null)
+ pWriter.flush();
+ }
+
+ /**
+ * Read in properties file and set instance variables.
+ *
+ * @param fName name of .properties file to read
+ * @return false if error occoured
+ */
+ protected boolean initPropFile(String fName)
+ {
+
+ Properties p = new Properties();
+
+ try
+ {
+
+ // Load named file into our properties block
+ FileInputStream fIS = new FileInputStream(fName);
+
+ p.load(fIS);
+
+ // Parse out any values that match our internal convenience variables
+ outputDir = p.getProperty("outputDir", outputDir);
+
+ // Validate the outputDir and use it to reset the logFileName
+ File oDir = new File(outputDir);
+
+ if (!oDir.exists())
+ {
+ if (!oDir.mkdirs())
+ {
+
+ // Error, we can't create the outputDir, default to current dir
+ println("<message desc=\"outputDir(" + outputDir
+ + ") does not exist, defaulting to .\"/>");
+
+ outputDir = ".";
+ }
+ }
+
+ // Verify inputDir as well
+ inputDir = p.getProperty("inputDir", inputDir);
+
+ File tDir = new File(inputDir);
+
+ if (!tDir.exists())
+ {
+ if (!tDir.mkdirs())
+ {
+
+ // Error, we can't create the inputDir, abort
+ println("<message desc=\"inputDir(" + inputDir
+ + ") does not exist, terminating test\"/>");
+
+ return false;
+ }
+ }
+
+ // Add on separators
+ inputDir += File.separator;
+ outputDir += File.separator;
+
+ // Each defaults to variable initializers
+ logFileName = p.getProperty("logFile", logFileName);
+ setOneFilenameRoot = p.getProperty("setOneFile",
+ setOneFilenameRoot);
+ setTwoFilenameRoot = p.getProperty("setTwoFile",
+ setTwoFilenameRoot);
+ setThreeFilenameRoot = p.getProperty("setThreeFile",
+ setThreeFilenameRoot);
+ paramName = p.getProperty("paramName", paramName);
+ paramVal = p.getProperty("paramVal", paramVal);
+ liaison = p.getProperty("liaison", liaison);
+
+ String numb;
+
+ numb = p.getProperty("numRunners");
+
+ if (numb != null)
+ {
+ try
+ {
+ numRunners = Integer.parseInt(numb);
+ }
+ catch (NumberFormatException numEx)
+ {
+
+ // no-op, leave set as default
+ println("<message desc=\"numRunners threw: "
+ + numEx.toString() + "\"/>");
+ }
+ }
+
+ numb = p.getProperty("numRunnerCalls");
+
+ if (numb != null)
+ {
+ try
+ {
+ numRunnerCalls = Integer.parseInt(numb);
+ }
+ catch (NumberFormatException numEx)
+ {
+
+ // no-op, leave set as default
+ println("<message desc=\"numRunnerCalls threw: "
+ + numEx.toString() + "\"/>");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ println("<arbitrary=\"initPropFile: " + fName + " threw: "
+ + e.toString() + "\">");
+
+ if (pWriter != null)
+ {
+ e.printStackTrace(pWriter);
+ }
+
+ e.printStackTrace();
+ println("</arbitrary>");
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Bottleneck output; goes to System.out and main's pWriter.
+ *
+ * NEEDSDOC @param s
+ */
+ protected void println(String s)
+ {
+
+ System.out.println(s);
+
+ if (pWriter != null)
+ pWriter.println(s);
+ }
+
+ /** A simple log output file for the main thread; each runner also has it's own. */
+ protected PrintWriter pWriter = null;
+
+ /**
+ * Worker method to setup a simple log output file.
+ *
+ * NEEDSDOC @param n
+ */
+ protected void createLogFile(String n)
+ {
+
+ try
+ {
+ pWriter = new PrintWriter(new FileWriter(n, true));
+ }
+ catch (Exception e)
+ {
+ System.err.println("<message desc=\"createLogFile threw: "
+ + e.toString() + "\"/>");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Startup the test from the command line.
+ *
+ * NEEDSDOC @param args
+ */
+ public static void main(String[] args)
+ {
+
+ if (args.length < 1)
+ {
+ System.err.println("ERROR! Must have at least one argument\n" + usage());
+
+ return; // Don't System.exit, it's not polite
+ }
+
+ TestMultiTypeThreads app = new TestMultiTypeThreads();
+ // semi-HACK: accept and ignore -load as first arg only
+ String propFileName = null;
+ if ("-load".equalsIgnoreCase(args[0]))
+ {
+ propFileName = args[1];
+ }
+ else
+ {
+ propFileName = args[0];
+ }
+ if (!app.initPropFile(propFileName)) // Side effect: creates pWriter for logging
+ {
+ System.err.println("ERROR! Could not read properties file: "
+ + propFileName);
+
+ return;
+ }
+
+ app.runTest();
+ }
+
+ /**
+ * Worker method to translate String to URI.
+ * Note: Xerces and Crimson appear to handle some URI references
+ * differently - this method needs further work once we figure out
+ * exactly what kind of format each parser wants (esp. considering
+ * relative vs. absolute references).
+ * @param String path\filename of test file
+ * @return URL to pass to SystemId
+ */
+ public static String filenameToURI(String filename)
+ {
+ File f = new File(filename);
+ String tmp = f.getAbsolutePath();
+ if (File.separatorChar == '\\') {
+ tmp = tmp.replace('\\', '/');
+ }
+ return "file:///" + tmp;
+ }
+} // end of class TestMultiTypeThreads
+
+/**
+ * Worker class to run a processor on a separate thread.
+ * <p>Currently, no automated validation is done, however most
+ * output files and all error logs are saved to disk allowing for
+ * later manual verification.</p>
+ */
+class TMTThreadsRunner implements Runnable
+{
+
+ /** NEEDSDOC Field xslStylesheet */
+ Templates xslStylesheet;
+
+ /** NEEDSDOC Field numProcesses */
+ int numProcesses;
+
+ /** NEEDSDOC Field runnerID */
+ String runnerID;
+
+ /** NEEDSDOC Field xmlName */
+ String xmlName;
+
+ /** NEEDSDOC Field xslName */
+ String xslName;
+
+ /** NEEDSDOC Field outName */
+ String outName;
+
+ /** NEEDSDOC Field paramName */
+ String paramName;
+
+ /** NEEDSDOC Field paramVal */
+ String paramVal;
+
+ /** NEEDSDOC Field liaison */
+ String liaison;
+
+ /** NEEDSDOC Field polite */
+ boolean polite = false; // if we should yield each loop
+
+ /** NEEDSDOC Field recreate */
+ boolean recreate = false; // if we should re-create a new processor each time
+
+ /** NEEDSDOC Field validate */
+ boolean validate = false; // if we should attempt to validate output files (FUTUREWORK)
+
+ /** NEEDSDOC Field reportMem */
+ boolean reportMem = false; // if we should report memory usage periodically
+
+ /** NEEDSDOC Field setParam */
+ boolean setParam = false; // if we should set our parameter or not
+
+ /** NEEDSDOC Field setParam */
+ String transformType = StreamSource.FEATURE;
+
+ /**
+ * Constructor TMTThreadsRunner
+ *
+ *
+ * NEEDSDOC @param params
+ * NEEDSDOC @param xslStylesheet
+ * NEEDSDOC @param numProcesses
+ */
+ TMTThreadsRunner(String[] params, Templates xslStylesheet,
+ int numProcesses)
+ {
+
+ this.xslStylesheet = xslStylesheet;
+ this.numProcesses = numProcesses;
+ this.runnerID = params[TestMultiTypeThreads.ID];
+ this.xmlName = params[TestMultiTypeThreads.XMLNAME]; // must already be legal URI
+ this.xslName = params[TestMultiTypeThreads.XSLNAME]; // must already be legal URI
+ this.outName = params[TestMultiTypeThreads.OUTNAME]; // must be local path/filename
+ this.paramName = params[TestMultiTypeThreads.PARAMNAME];
+ this.paramVal = params[TestMultiTypeThreads.PARAMVAL];
+
+ if (params[TestMultiTypeThreads.OPTIONS].indexOf("polite") > 0)
+ polite = true;
+
+ if (params[TestMultiTypeThreads.OPTIONS].indexOf("recreate") > 0)
+ recreate = true;
+
+ if (params[TestMultiTypeThreads.OPTIONS].indexOf("validate") > 0)
+ validate = true;
+
+ // Optimization: only report memory if asked to and we're
+ // in the first iteration of runners created
+ if ((params[TestMultiTypeThreads.OPTIONS].indexOf("memory") > 0)
+ && (this.runnerID.indexOf("0") >= 0))
+ reportMem = true;
+
+ if (params[TestMultiTypeThreads.OPTIONS].indexOf("param") > 0)
+ setParam = true;
+
+ if (params[TestMultiTypeThreads.LIAISON] != null) // TRAX unused
+ liaison = params[TestMultiTypeThreads.LIAISON];
+
+ if (params[TestMultiTypeThreads.TRANSFORM_TYPE] != null)
+ transformType = params[TestMultiTypeThreads.TRANSFORM_TYPE];
+ }
+
+ /**
+ * Bottleneck output; both to System.out and to our private errWriter.
+ *
+ * NEEDSDOC @param s
+ */
+ protected void println(String s)
+ {
+
+ System.out.println(s);
+
+ if (errWriter != null)
+ errWriter.println(s);
+ }
+
+ /**
+ * Bottleneck output; both to System.out and to our private errWriter.
+ *
+ * NEEDSDOC @param s
+ */
+ protected void print(String s)
+ {
+
+ System.out.print(s);
+
+ if (errWriter != null)
+ errWriter.print(s);
+ }
+
+ /** NEEDSDOC Field errWriter */
+ PrintWriter errWriter = null;
+
+ /**
+ * NEEDSDOC Method createErrWriter
+ *
+ */
+ protected void createErrWriter()
+ {
+
+ try
+ {
+ errWriter = new PrintWriter(new FileWriter(outName + ".log"),
+ true);
+ }
+ catch (Exception e)
+ {
+ System.err.println("<message desc=\"" + runnerID + ":threw: "
+ + e.toString() + "\"/>");
+ }
+ }
+
+ /** Main entrypoint; loop and perform lots of processes. */
+ public void run()
+ {
+
+ int i = 0; // loop counter; used for error reporting
+
+ createErrWriter();
+ println("<?xml version=\"1.0\"?>");
+ println("<testrunner desc=\"" + runnerID + ":started\" fileName=\""
+ + xslName + "\">");
+
+ TransformerFactory factory = null;
+
+ try
+ {
+
+ // Each runner creates it's own processor for use and it's own error log
+ factory = TransformerFactory.newInstance();
+
+ println("<arbitrary desc=\"" + runnerID + ":processing\">");
+ }
+ catch (Throwable ex)
+ { // If we got here, just log it and bail, no sense continuing
+ println("<throwable desc=\"" + ex.toString() + "\"><![CDATA[");
+ ex.printStackTrace(errWriter);
+ println("\n</throwable>");
+ println("<message desc=\"" + runnerID + ":complete-ERROR:after:"
+ + i + "\"/>");
+ println("</testrunner>");
+
+ if (errWriter != null)
+ errWriter.close();
+
+ return;
+ }
+
+ try
+ {
+
+ // Loop away...
+ for (i = 0; i < numProcesses; i++)
+ {
+
+ // Run a process using the pre-compiled stylesheet we were construced with
+ {
+ Transformer transformer1 = xslStylesheet.newTransformer();
+ if (transformType == DOMSource.FEATURE)
+ {
+ doDOMTransform(transformer1, xmlName, outName + "d.out", "d");
+ }
+ else if (transformType == SAXSource.FEATURE)
+ {
+ doSAXTransform(xslName, xmlName, outName + "x.out", "x");
+ }
+ else if (transformType == StreamSource.FEATURE)
+ {
+ // Call String ctor so we don't have to setSystemId
+ Result result1 = new StreamResult(outName + "t.out");
+
+ if (setParam)
+ transformer1.setParameter(paramName, paramVal);
+
+ print("t"); // Note presence of this in logs shows which process threw an exception
+ transformer1.transform(new StreamSource(xmlName), result1);
+ }
+ else
+ {
+ throw new RuntimeException("unsupported transformType: " + transformType);
+ }
+
+ // Temporary vars go out of scope for cleanup here
+ }
+
+ // Now process something with a newly-processed stylesheet
+ {
+ Templates templates2 =
+ factory.newTemplates(new StreamSource(xslName));
+ Transformer transformer2 = templates2.newTransformer();
+ if (transformType == DOMSource.FEATURE)
+ {
+ doDOMTransform(transformer2, xmlName, outName + "_D.out", "D");
+ }
+ else if (transformType == SAXSource.FEATURE)
+ {
+ doSAXTransform(xslName, xmlName, outName + "_X.out", "X");
+ }
+ else // if (transformType == StreamSource.FEATURE)
+ {
+ Result result2 = new StreamResult(outName + "_T.out");
+
+ if (setParam)
+ transformer2.setParameter(paramName, paramVal);
+
+ print("T"); // Note presence of this in logs shows which process threw an exception
+ transformer2.transform(new StreamSource(xmlName), result2);
+ }
+ }
+
+ // if asked, report memory statistics
+ if (reportMem)
+ {
+ Runtime r = Runtime.getRuntime();
+
+ r.gc();
+
+ long freeMemory = r.freeMemory();
+ long totalMemory = r.totalMemory();
+
+ println("<statistic desc=\"" + runnerID
+ + ":memory:longval-free:doubleval-total\">");
+ println("<longval>" + freeMemory + "</longval>");
+ println("<doubleval>" + totalMemory + "</doubleval>");
+ println("</statistic>");
+ }
+
+ // if we're polite, let others play for a bit
+ if (polite)
+ java.lang.Thread.yield();
+ }
+
+ // IF we get here, we worked without exceptions (presumably successfully)
+ println("</arbitrary>");
+ println("<message desc=\"" + runnerID + ":complete-OK:after:"
+ + numProcesses + "\"/>");
+ }
+
+ // Separate messages for each kind of exception
+ catch (TransformerException te)
+ {
+ println("\n<TransformerException desc=\"" + te.toString() + "\">");
+ logStackTrace(te, errWriter);
+ logContainedException(te, errWriter);
+ println("</TransformerException>");
+ println("</arbitrary>");
+ println("<message desc=\"" + runnerID + ":complete-ERROR:after:"
+ + i + "\"/>");
+ }
+ catch (Throwable ex)
+ {
+ logThrowable(ex, errWriter);
+ println("</arbitrary>");
+ println("<message desc=\"" + runnerID + ":complete-ERROR:after:"
+ + i + "\"/>");
+ }
+ finally
+ {
+
+ // Cleanup our references, etc.
+ println("</testrunner>");
+
+ if (errWriter != null)
+ errWriter.close();
+
+ runnerID = null;
+ xmlName = null;
+ xslName = null;
+ xslStylesheet = null;
+ outName = null;
+ }
+ } // end of run()...
+
+ /** Worker method to do a specific type of transform */
+ private void doDOMTransform(Transformer t, String xmlName, String outName, String marker)
+ throws Exception
+ {
+ if (setParam)
+ t.setParameter(paramName, paramVal);
+
+ // Parse in the xml data into a DOM
+ DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
+ dfactory.setNamespaceAware(true);
+ DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
+ Node xmlDoc = docBuilder.parse(new InputSource(xmlName));
+ Source xmlSource = new DOMSource(xmlDoc);
+ xmlSource.setSystemId(xmlName);
+
+ // Prepare a result and transform it into a DOM
+ org.w3c.dom.Document outNode = docBuilder.newDocument();
+ print(marker); // Note presence of this in logs shows which process threw an exception
+ t.transform(xmlSource, new DOMResult(outNode));
+
+ // Now serialize output to disk with identity transformer
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer serializer = factory.newTransformer();
+ serializer.transform(new DOMSource(outNode),
+ new StreamResult(new FileOutputStream(outName)));
+ // do we need to FileOutputStream.close()?
+ }
+
+ /** Worker method to do a specific type of transform */
+ private void doSAXTransform(String xslName, String xmlName, String outName, String marker)
+ throws Exception
+ {
+ TransformerFactory factory = TransformerFactory.newInstance();
+ // should check for SAXResult.FEATURE first!
+ SAXTransformerFactory sfactory = ((SAXTransformerFactory) factory);
+
+ // Create an Document node as the root for the output.
+ DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
+ Document outNode = docBuilder.newDocument();
+
+ // Create a ContentHandler that can liston to SAX events
+ // and transform the output to DOM nodes.
+ TransformerHandler handler = sfactory.newTransformerHandler(new StreamSource(xslName));
+ handler.setResult(new DOMResult(outNode));
+
+ // Create a reader and set it's ContentHandler to be the
+ // transformer.
+ SAXParserFactory spfactory = SAXParserFactory.newInstance();
+ spfactory.setNamespaceAware(true);
+ SAXParser jaxpParser = spfactory.newSAXParser();
+ XMLReader reader = jaxpParser.getXMLReader();
+
+ reader.setContentHandler(handler);
+ reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+
+ // Send the SAX events from the parser to the transformer,
+ // and thus to the DOM tree.
+ print(marker); // Note presence of this in logs shows which process threw an exception
+ handler.setSystemId(xmlName);
+ reader.parse(xmlName);
+
+ // Serialize the DOM tree out
+ FileOutputStream fos = new FileOutputStream(outName);
+ Transformer serializer = factory.newTransformer();
+ //serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+ //serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ serializer.transform(new DOMSource(outNode), new StreamResult(fos));
+ }
+
+ /**
+ * NEEDSDOC Method logContainedException
+ *
+ *
+ * NEEDSDOC @param parent
+ * NEEDSDOC @param p
+ */
+ private void logContainedException(TransformerException parent, PrintWriter p)
+ {
+
+ Throwable containedException = parent.getException();
+
+ if (null != containedException)
+ {
+ println("<containedexception desc=\""
+ + containedException.toString() + "\">");
+ logStackTrace(containedException, p);
+ println("</containedexception>");
+ }
+ }
+
+ /**
+ * NEEDSDOC Method logThrowable
+ *
+ *
+ * NEEDSDOC @param t
+ * NEEDSDOC @param p
+ */
+ private void logThrowable(Throwable t, PrintWriter p)
+ {
+
+ println("\n<throwable desc=\"" + t.toString() + "\">");
+ logStackTrace(t, p);
+ println("</throwable>");
+ }
+
+ /**
+ * NEEDSDOC Method logStackTrace
+ *
+ *
+ * NEEDSDOC @param t
+ * NEEDSDOC @param p
+ */
+ private void logStackTrace(Throwable t, PrintWriter p)
+ {
+
+ // Should check if (errWriter == null)
+ println("<stacktrace><![CDATA[");
+ t.printStackTrace(p);
+
+ // Could also echo to stdout, but not really worth it
+ println("]]></stacktrace>");
+ }
+} // end of class TMTThreadsRunner...
+
+// END OF FILE