| /* |
| * 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 |