diff options
Diffstat (limited to 'test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java')
-rw-r--r-- | test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java | 1013 |
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 |