You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by cu...@locus.apache.org on 2000/11/16 19:58:21 UTC
cvs commit: xml-xalan/test/java/src/org/apache/qetest/trax TestMultiTypeThreads.java
curcuru 00/11/16 10:58:21
Added: test/java/src/org/apache/qetest/trax
TestMultiTypeThreads.java
Log:
Manually verified test with multiple threads all executing
TRAX transforms of different types: SAX, DOM, Stream
Revision Changes Path
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/TestMultiTypeThreads.java
Index: TestMultiTypeThreads.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2000, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
*
* TestMultiTypeThreads.java
*
*/
package org.apache.qetest.trax;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.StringTokenizer;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
// Needed DOM classes
import org.w3c.dom.Node;
import org.w3c.dom.Document;
// For optional URI/URLs instead of string filenames
import java.net.URL;
import java.net.MalformedURLException;
// Import all relevant TRAX packages
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.*; // We assume Features.STREAM for some tests
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
// HACK: Use Xalan's Serializers - should be changed
import org.xml.sax.XMLReader;
import org.xml.sax.ContentHandler;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLReaderFactory;
//-------------------------------------------------------------------------
/**
* 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 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 =
getURLFromString(inputDir + setOneFilenameRoot + ".xsl",
null).toExternalForm();
String setTwoURL =
getURLFromString(inputDir + setTwoFilenameRoot + ".xsl",
null).toExternalForm();
String setThreeURL =
getURLFromString(inputDir + setThreeFilenameRoot + ".xsl",
null).toExternalForm();
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] = "file:" + inputDir + setOneFilenameRoot
+ ".xml";
rValues[XSLNAME] = 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] = "file:" + inputDir + setTwoFilenameRoot
+ ".xml";
rValues[XSLNAME] = 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] = "file:" + inputDir + setThreeFilenameRoot
+ ".xml";
rValues[XSLNAME] = 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 one argument\n" + usage());
return; // Don't System.exit, it's not polite
}
TestMultiTypeThreads app = new TestMultiTypeThreads();
if (!app.initPropFile(args[0])) // Side effect: creates pWriter for logging
{
System.err.println("ERROR! Could not read properties file: "
+ args[0]);
return;
}
app.runTest();
}
// /////////////////// HACK - added from Xalan1 org.apache.xalan.xslt.Process /////////////////////
/**
* Take a user string and try and parse XML, and also return the url.
*
* @todo remove this; make URL's in a simpler manner!!!
* NEEDSDOC @param urlString
* NEEDSDOC @param base
*
* NEEDSDOC ($objectName$) @return
* @exception SAXException thrown if we really really can't create the URL
*/
public static URL getURLFromString(String urlString, String base)
throws SAXException
{
String origURLString = urlString;
String origBase = base;
// System.out.println("getURLFromString - urlString: "+urlString+", base: "+base);
Object doc;
URL url = null;
int fileStartType = 0;
try
{
if (null != base)
{
if (base.toLowerCase().startsWith("file:/"))
{
fileStartType = 1;
}
else if (base.toLowerCase().startsWith("file:"))
{
fileStartType = 2;
}
}
boolean isAbsoluteURL;
// From http://www.ics.uci.edu/pub/ietf/uri/rfc1630.txt
// A partial form can be distinguished from an absolute form in that the
// latter must have a colon and that colon must occur before any slash
// characters. Systems not requiring partial forms should not use any
// unencoded slashes in their naming schemes. If they do, absolute URIs
// will still work, but confusion may result.
int indexOfColon = urlString.indexOf(':');
int indexOfSlash = urlString.indexOf('/');
if ((indexOfColon != -1) && (indexOfSlash != -1)
&& (indexOfColon < indexOfSlash))
{
// The url (or filename, for that matter) is absolute.
isAbsoluteURL = true;
}
else
{
isAbsoluteURL = false;
}
if (isAbsoluteURL || (null == base) || (base.length() == 0))
{
try
{
url = new URL(urlString);
}
catch (MalformedURLException e){}
}
// The Java URL handling doesn't seem to handle relative file names.
else if (!((urlString.charAt(0) == '.') || (fileStartType > 0)))
{
try
{
URL baseUrl = new URL(base);
url = new URL(baseUrl, urlString);
}
catch (MalformedURLException e){}
}
if (null == url)
{
// Then we're going to try and make a file URL below, so strip
// off the protocol header.
if (urlString.toLowerCase().startsWith("file:/"))
{
urlString = urlString.substring(6);
}
else if (urlString.toLowerCase().startsWith("file:"))
{
urlString = urlString.substring(5);
}
}
if ((null == url) && ((null == base) || (fileStartType > 0)))
{
if (1 == fileStartType)
{
if (null != base)
base = base.substring(6);
fileStartType = 1;
}
else if (2 == fileStartType)
{
if (null != base)
base = base.substring(5);
fileStartType = 2;
}
File f = new File(urlString);
if (!f.isAbsolute() && (null != base))
{
// String dir = f.isDirectory() ? f.getAbsolutePath() : f.getParent();
// System.out.println("prebuiltUrlString (1): "+base);
StringTokenizer tokenizer = new StringTokenizer(base,
"\\/");
String fixedBase = null;
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (null == fixedBase)
{
// Thanks to Rick Maddy for the bug fix for UNIX here.
if (base.charAt(0) == '\\'
|| base.charAt(0) == '/')
{
fixedBase = File.separator + token;
}
else
{
fixedBase = token;
}
}
else
{
fixedBase += File.separator + token;
}
}
// System.out.println("rebuiltUrlString (1): "+fixedBase);
f = new File(fixedBase);
String dir = f.isDirectory()
? f.getAbsolutePath() : f.getParent();
// System.out.println("dir: "+dir);
// System.out.println("urlString: "+urlString);
// f = new File(dir, urlString);
// System.out.println("f (1): "+f.toString());
// urlString = f.getAbsolutePath();
f = new File(urlString);
boolean isAbsolute = f.isAbsolute()
|| (urlString.charAt(0) == '\\')
|| (urlString.charAt(0) == '/');
if (!isAbsolute)
{
// Getting more and more ugly...
if (dir.charAt(dir.length() - 1)
!= File.separator.charAt(0)
&& urlString.charAt(0)
!= File.separator.charAt(0))
{
urlString = dir + File.separator + urlString;
}
else
{
urlString = dir + urlString;
}
// System.out.println("prebuiltUrlString (2): "+urlString);
tokenizer = new StringTokenizer(urlString, "\\/");
String rebuiltUrlString = null;
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (null == rebuiltUrlString)
{
// Thanks to Rick Maddy for the bug fix for UNIX here.
if (urlString.charAt(0) == '\\'
|| urlString.charAt(0) == '/')
{
rebuiltUrlString = File.separator + token;
}
else
{
rebuiltUrlString = token;
}
}
else
{
rebuiltUrlString += File.separator + token;
}
}
// System.out.println("rebuiltUrlString (2): "+rebuiltUrlString);
if (null != rebuiltUrlString)
urlString = rebuiltUrlString;
}
// System.out.println("fileStartType: "+fileStartType);
if (1 == fileStartType)
{
if (urlString.charAt(0) == '/')
{
urlString = "file://" + urlString;
}
else
{
urlString = "file:/" + urlString;
}
}
else if (2 == fileStartType)
{
urlString = "file:" + urlString;
}
try
{
// System.out.println("Final before try: "+urlString);
url = new URL(urlString);
}
catch (MalformedURLException e)
{
// System.out.println("Error trying to make URL from "+urlString);
}
}
}
if (null == url)
{
// The sun java VM doesn't do this correctly, but I'll
// try it here as a second-to-last resort.
if ((null != origBase) && (origBase.length() > 0))
{
try
{
URL baseURL = new URL(origBase);
// System.out.println("Trying to make URL from "+origBase+" and "+origURLString);
url = new URL(baseURL, origURLString);
// System.out.println("Success! New URL is: "+url.toString());
}
catch (MalformedURLException e)
{
// System.out.println("Error trying to make URL from "+origBase+" and "+origURLString);
}
}
if (null == url)
{
try
{
String lastPart;
if (null != origBase)
{
File baseFile = new File(origBase);
if (baseFile.isDirectory())
{
lastPart =
new File(baseFile,
urlString).getAbsolutePath();
}
else
{
String parentDir = baseFile.getParent();
lastPart =
new File(parentDir,
urlString).getAbsolutePath();
}
}
else
{
lastPart = new File(urlString).getAbsolutePath();
}
// Hack
// if((lastPart.charAt(0) == '/') && (lastPart.charAt(2) == ':'))
// lastPart = lastPart.substring(1, lastPart.length() - 1);
String fullpath;
if (lastPart.charAt(0) == '\\'
|| lastPart.charAt(0) == '/')
{
fullpath = "file://" + lastPart;
}
else
{
fullpath = "file:" + lastPart;
}
url = new URL(fullpath);
}
catch (MalformedURLException e2)
{
throw new SAXException("Cannot create url for: "
+ urlString, e2);
//XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CREATE_URL, new Object[]{urlString}),e2); //"Cannot create url for: " + urlString, e2 );
}
}
}
}
catch (SecurityException se)
{
try
{
url = new URL("http://xml.apache.org/xslt/"
+ java.lang.Math.random()); // dummy
}
catch (MalformedURLException e2)
{
// I give up
}
}
// System.out.println("url: "+url.toString());
return url;
}
} // 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];
this.xslName = params[TestMultiTypeThreads.XSLNAME];
this.outName = params[TestMultiTypeThreads.OUTNAME];
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;
if (params[TestMultiTypeThreads.OPTIONS].indexOf("memory") > 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();
// Munge the input filenames to be URLs
xmlName = TestMultiTypeThreads.getURLFromString(xmlName,
null).toExternalForm();
xslName = TestMultiTypeThreads.getURLFromString(xslName,
null).toExternalForm();
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 + ".out", "d");
}
else if (transformType == SAXSource.FEATURE)
{
doSAXTransform(xslName, xmlName, outName + ".out", "x");
}
else if (transformType == StreamSource.FEATURE)
{
FileOutputStream resultStream1 =
new FileOutputStream(outName + ".out");
Result result1 = new StreamResult(resultStream1);
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);
resultStream1.close();
}
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 + "_.out", "D");
}
else if (transformType == SAXSource.FEATURE)
{
doSAXTransform(xslName, xmlName, outName + "_.out", "X");
}
else // if (transformType == StreamSource.FEATURE)
{
FileOutputStream resultStream2 =
new FileOutputStream(outName + "_.out");
Result result2 = new StreamResult(resultStream2);
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);
resultStream2.close();
}
}
// 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
{
// Parse in the xml data into a DOM
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
Node xmlDoc = docBuilder.parse(new InputSource(xmlName));
// Prepare a result and transform it into a DOM
org.w3c.dom.Document outNode = docBuilder.newDocument();
if (setParam)
t.setParameter(paramName, paramVal);
print(marker); // Note presence of this in logs shows which process threw an exception
t.transform(new DOMSource(xmlDoc), 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.
XMLReader reader = null;
// Use JAXP1.1 ( if possible )
javax.xml.parsers.SAXParserFactory spfactory = javax.xml.parsers.SAXParserFactory.newInstance();
spfactory.setNamespaceAware(true);
javax.xml.parsers.SAXParser jaxpParser = spfactory.newSAXParser();
reader = jaxpParser.getXMLReader();
if (reader == null)
reader = XMLReaderFactory.createXMLReader();
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
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)
{
Exception 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