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/02 00:27:05 UTC
cvs commit: xml-xalan/test/java/src/org/apache/qetest/xslwrapper LotusXSLWrapper.java ProcessorWrapper.java ProcessorWrapper.properties SaxonWrapper.class SaxonWrapper.java TraxWrapper.java XTWrapper.class XTWrapper.java XalanWrapper.java package.html
curcuru 00/11/01 15:27:04
Added: test/java/bin ant.jar antRun antRun.bat
test/java/src/org/apache/qetest/trax LoggingURIResolver.java
ProcessorAPITest.java ResultAPITest.java
TemplatesAPITest.java TestThreads.java
TransformerAPITest.java package.html
test/java/src/org/apache/qetest/xalanj1 ParamTest.java
package.html
test/java/src/org/apache/qetest/xsl CConformanceTest.java
ConformanceDirRules.java
ConformanceErrFileRules.java
ConformanceFileRules.java ConformanceTest.java
LoggingEntityResolver.java
LoggingSAXErrorHandler.java PerformanceTest.java
XHTComparator.java XHTFileCheckService.java
XSLDirectoryIterator.java XSLProcessorTestBase.java
XSLTestfileInfo.java package.html
test/java/src/org/apache/qetest/xslwrapper
LotusXSLWrapper.java ProcessorWrapper.java
ProcessorWrapper.properties SaxonWrapper.class
SaxonWrapper.java TraxWrapper.java XTWrapper.class
XTWrapper.java XalanWrapper.java package.html
Log:
Xalan Java-based test automation
Revision Changes Path
1.1 xml-xalan/test/java/bin/ant.jar
<<Binary file>>
1.1 xml-xalan/test/java/bin/antRun
Index: antRun
===================================================================
#! /bin/sh
# Args: DIR command
cd $1
CMD=$2
shift
shift
if test -f $CMD.sh; then
CMD="sh $CMD.sh"
fi
echo $CMD $@ | sh
1.1 xml-xalan/test/java/bin/antRun.bat
Index: antRun.bat
===================================================================
@echo off
cd %1
set ANT_RUN_CMD=%2
shift
shift
%ANT_RUN_CMD% %1 %2 %3 %4 %5 %6 %7 %8 %9
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/LoggingURIResolver.java
Index: LoggingURIResolver.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/>.
*/
/*
*
* LoggingURIResolver.java
*
*/
package org.apache.qetest.trax;
import org.apache.qetest.*;
import org.apache.trax.URIResolver;
import org.apache.trax.TransformException;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
//-------------------------------------------------------------------------
/**
* Implementation of URIResolver that logs all calls.
* Currently just provides default service; returns null.
* @author shane_curcuru@lotus.com
* @version $Id: LoggingURIResolver.java,v 1.1 2000/11/01 23:26:54 curcuru Exp $
*/
public class LoggingURIResolver implements URIResolver
{
/** No-op ctor since it's often useful to have one. */
public LoggingURIResolver(){}
/**
* Ctor that calls setReporter automatically.
*
* NEEDSDOC @param r
*/
public LoggingURIResolver(Reporter r)
{
setReporter(r);
}
/** Our Reporter, who we tell all our secrets to. */
private Reporter reporter;
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC @param r
*/
public void setReporter(Reporter r)
{
if (r != null)
reporter = r;
}
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC ($objectName$) @return
*/
public Reporter getReporter()
{
return (reporter);
}
/** Prefixed to all reporter msg output. */
private String prefix = "UR:";
/** Counters for how many URIs we've 'resolved'. */
private int URICtr = 0;
/**
* Accesor methods for URI counter.
*
* NEEDSDOC ($objectName$) @return
*/
public int getURICtr()
{
return URICtr;
}
/**
* Cheap-o string representation of our state.
*
* NEEDSDOC ($objectName$) @return
*/
public String getCounterString()
{
return (prefix + "URIs: " + getURICtr());
}
/** Cheap-o string representation of last entity we resolved. */
private String lastURI = null;
/**
* NEEDSDOC Method setLastURI
*
*
* NEEDSDOC @param s
*/
protected void setLastURI(String s)
{
lastURI = s;
}
/**
* Accessor for string representation of last entity we resolved.
*
* NEEDSDOC ($objectName$) @return
*/
public String getLastURI()
{
return lastURI;
}
/** What loggingLevel to use for reporter.logMsg(). */
private int level = Reporter.DEFAULT_LOGGINGLEVEL;
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC @param l
*/
public void setLoggingLevel(int l)
{
level = l;
}
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC ($objectName$) @return
*/
public int getLoggingLevel()
{
return level;
}
/**
* Cheap-o utility to get a string value.
* @todo improve string return value
*
* NEEDSDOC @param i
*
* NEEDSDOC ($objectName$) @return
*/
private String getString(InputSource i)
{
return i.toString();
}
/**
* Implement this method: just returns null for now.
* Also saves the last entity for later retrieval, and counts
* how many entities we've 'resolved' overall.
* @todo have a settable property to actually return as the InputSource
* @param inputSource The value returned from the EntityResolver.
* @return (null currently) a DOM node that represents the resolution of the URI
* @exception TransformException never thrown currently
*/
public Node getDOMNode(InputSource inputSource) throws TransformException
{
URICtr++;
setLastURI(getString(inputSource));
if (reporter != null)
{
reporter.logMsg(level,
prefix + getLastURI() + " " + getCounterString());
}
return null;
}
/**
* Implement this method: just returns null for now.
* Also saves the last entity for later retrieval, and counts
* how many entities we've 'resolved' overall.
* @todo have a settable property to actually return as the InputSource
* @param inputSource The value returned from the EntityResolver.
* @return (null currently) a SAX2 parser to use with the InputSource.
* @exception TransformException never thrown currently
*/
public XMLReader getXMLReader(InputSource inputSource)
throws TransformException
{
URICtr++;
setLastURI(getString(inputSource));
if (reporter != null)
{
reporter.logMsg(level,
prefix + getLastURI() + " " + getCounterString());
}
return null;
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/ProcessorAPITest.java
Index: ProcessorAPITest.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/>.
*/
/*
*
* ProcessorAPITest.java
*
*/
package org.apache.qetest.trax;
import org.apache.qetest.*;
import org.apache.qetest.xsl.*;
// Just import the whole trax package; note the packaging is likely to change
import org.apache.trax.*;
// Use Serializer classes from Xalan distro
import org.apache.serialize.OutputFormat;
import org.apache.serialize.Serializer;
import org.apache.serialize.SerializerFactory;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.Parser;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.XMLReader;
import org.xml.sax.ContentHandler;
// Needed DOM classes
import org.w3c.dom.Node;
// javax JAXP classes for parser pluggability
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
// java classes
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.Properties;
//-------------------------------------------------------------------------
/**
* Basic API coverage test for the Processor class of TRAX.
* Currently assumes you're using Xalan 2.x.
* @author shane_curcuru@lotus.com
*/
public class ProcessorAPITest extends XSLProcessorTestBase
{
/**
* Cheap-o filename for various output files.
*
*/
protected OutputNameManager outNames;
/** Cheap-o filename set for both API tests and exampleSimple. */
protected XSLTestfileInfo simpleTest = new XSLTestfileInfo();
/** Cache the relevant system property. */
protected String saveXSLTProp = null;
/** NEEDSDOC Field TRAX_PROCESSOR */
public static final String TRAX_PROCESSOR = "trax.processor";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = TRAX_PROCESSOR + "."
+ XSLT;
/** Allow user to override our default of Xalan 2.x processor classname. */
public static final String XALAN_CLASSNAME =
"org.apache.xalan.processor.StylesheetProcessor";
/** NEEDSDOC Field PROCESSOR_CLASSNAME */
protected String PROCESSOR_CLASSNAME = "processorClassname";
/** NEEDSDOC Field processorClassname */
protected String processorClassname = XALAN_CLASSNAME;
/** NEEDSDOC Field INVALID_NAME */
public static final String INVALID_NAME = "invalid.name";
/** NEEDSDOC Field PROPERTY_LEXICAL_HANDLER */
public static final String PROPERTY_LEXICAL_HANDLER =
"http://xml.org/sax/properties/lexical-handler";
/** NEEDSDOC Field FEATURE_DOM_INPUT */
public static final String FEATURE_DOM_INPUT =
"http://xml.org/trax/features/dom/input";
/** NEEDSDOC Field FEATURE_SAX_INPUT */
public static final String FEATURE_SAX_INPUT =
"http://xml.org/trax/features/sax/input";
/** NEEDSDOC Field XAPI */
public static final String XAPI = "trax";
/** Default ctor initializes test name, comment, numTestCases. */
public ProcessorAPITest()
{
numTestCases = 4; // REPLACE_num
testName = "ProcessorAPITest";
testComment =
"Basic API coverage test for the Processor class of TRAX";
}
/**
* Initialize this test - Set names of xml/xsl test files, cache system property.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Used for all tests; just dump files in xapi subdir
File outSubDir = new File(outputDir + File.separator + XAPI);
if (!outSubDir.mkdirs())
reporter.logWarningMsg("Could not create output dir: "
+ outSubDir);
outNames = new OutputNameManager(outputDir + File.separator + XAPI
+ File.separator + testName, ".out");
// Used for API coverage and exampleSimple
String testBasePath = inputDir + File.separator + XAPI
+ File.separator;
String goldBasePath = goldDir + File.separator + XAPI
+ File.separator;
simpleTest.xmlName = testBasePath + "ProcessorAPITest.xml";
simpleTest.inputName = testBasePath + "ProcessorAPITest.xsl";
simpleTest.goldName = goldBasePath + "ProcessorAPITest.out";
// Cache trax system property
saveXSLTProp = System.getProperty(TRAX_PROCESSOR_XSLT);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ saveXSLTProp);
// Check if user wants to use a processor other than Xalan 2.x
processorClassname = testProps.getProperty(PROCESSOR_CLASSNAME,
XALAN_CLASSNAME);
reporter.logInfoMsg(PROCESSOR_CLASSNAME + " property is: "
+ processorClassname);
return true;
}
/**
* Cleanup this test - reset the cached system property trax.processor.xslt.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileClose(Properties p)
{
if (saveXSLTProp == null)
{
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
}
else
{
System.getProperties().put(TRAX_PROCESSOR_XSLT, saveXSLTProp);
}
return true;
}
/**
* TRAX Processor: cover static methods (creating processors).
* Simple coverage tests; most should work with any trax processor <b>but</b>
* we explicitly set the trax.processor.xslt property to the Xalan 2.x class.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase1()
{
reporter.testCaseInit(
"TRAX Processor: cover static methods (creating processors)");
// To be thorough, we should call Processor.getPlatformDefaultProcessor() and log it's value
// But: it's not in the trax spec yet (Sep-00)
// Some negative test cases: bad processor types
boolean bit = true;
try
{
Object o = Processor.newInstance(INVALID_NAME);
}
catch (ProcessorFactoryException pfe)
{
reporter.checkPass("newInstance(" + INVALID_NAME
+ ")1 properly threw: " + pfe.toString());
bit = false;
}
if (bit)
reporter.checkFail("newInstance(" + INVALID_NAME
+ ")1 did not throw exception");
System.getProperties().put(TRAX_PROCESSOR + "." + INVALID_NAME,
"this.class.does.not.exist");
bit = true;
try
{
Object o = Processor.newInstance(INVALID_NAME);
}
catch (ProcessorFactoryException pfe)
{
reporter.checkPass("newInstance(" + INVALID_NAME
+ ")2 properly threw: " + pfe.toString());
bit = false;
}
if (bit)
reporter.checkFail("newInstance(" + INVALID_NAME
+ ")2 did not throw exception");
// Negative test case: default is not valid, property is not valid
System.getProperties().put(TRAX_PROCESSOR_XSLT,
"this.class.does.not.exist");
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property set to: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(INVALID_NAME);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(INVALID_NAME)");
bit = true;
try
{
Object o = Processor.newInstance(XSLT);
}
catch (ProcessorFactoryException pfe)
{
reporter.checkPass(
"newInstance(xslt)3 of invalid default and prop properly threw: "
+ pfe.toString());
bit = false;
}
if (bit)
reporter.checkFail(
"newInstance(xslt)3 of invalid default and prop did not throw exception");
// Negative test case: default is valid, property is not valid
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
bit = true;
try
{
Object o = Processor.newInstance(XSLT);
}
catch (ProcessorFactoryException pfe)
{
reporter.checkPass(
"newInstance(xslt)4 of valid default and invalid prop properly threw: "
+ pfe.toString());
bit = false;
}
if (bit)
reporter.checkFail(
"newInstance(xslt)4 of valid default and invalid prop did not throw exception");
// Positive test cases: property is valid Xalan 2.x, default is not
Processor p = null;
System.getProperties().put(TRAX_PROCESSOR_XSLT, processorClassname);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property set to: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(INVALID_NAME);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(INVALID_NAME)");
try
{
p = Processor.newInstance(XSLT);
reporter.checkBool(
(p != null), true,
"newInstance(xslt)5 of invalid default but prop:Xalan 2.x");
}
catch (ProcessorFactoryException pfe)
{
reporter.checkFail(
"newInstance(xslt)5 of invalid default but prop:Xalan 2.x threw: "
+ pfe.toString());
}
p = null;
// Positive test case: property is null, default is valid
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
try
{
p = Processor.newInstance(XSLT);
reporter.checkBool(
(p != null), true,
"newInstance(xslt)6 of default:Xalan 2.x but prop:null");
}
catch (ProcessorFactoryException pfe)
{
reporter.checkFail(
"newInstance(xslt)6 of default:Xalan 2.x but prop:null threw: "
+ pfe.toString());
}
// Reset the property to what it was before the testCase started
if (saveXSLTProp == null)
{
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
}
else
{
System.getProperties().put(TRAX_PROCESSOR_XSLT, saveXSLTProp);
}
reporter.testCaseClose();
return true;
}
/**
* TRAX Processor: cover set/get instance methods.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase2()
{
reporter.testCaseInit(
"TRAX Processor: cover set/get instance methods");
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
Processor p = null;
try
{
p = Processor.newInstance(XSLT);
if (p == null)
{
reporter.checkFail(
"Processor is null; cannot continue testcase");
return false;
}
}
catch (ProcessorFactoryException pfe)
{ // No-op
}
// Testing SAX get/set features and properties - both negative and positive tests
boolean bit = true;
try
{
p.setFeature(INVALID_NAME, true);
}
catch (Exception e)
{
reporter.checkPass("setFeature(" + INVALID_NAME
+ ", true) properly threw: " + e.toString());
bit = false;
}
if (bit)
reporter.checkFail("setFeature(" + INVALID_NAME
+ ", true) did not throw exception");
bit = true;
try
{
bit = p.getFeature(INVALID_NAME);
}
catch (Exception e)
{
reporter.checkPass("getFeature(" + INVALID_NAME
+ ") properly threw: " + e.toString());
bit = false;
}
if (bit)
reporter.checkFail("getFeature(" + INVALID_NAME
+ ") did not throw exception");
bit = false;
try
{
// We presume this is supported, since we use it later on
bit = p.getFeature(FEATURE_DOM_INPUT);
reporter.check(bit, true,
"getFeature(" + FEATURE_DOM_INPUT
+ ") must be true for Xalan 2.x");
}
catch (Exception e)
{
reporter.checkFail("getFeature(" + FEATURE_DOM_INPUT
+ ") threw: " + e.toString());
}
bit = false;
try
{
// We presume this is supported, since we use it later on
bit = p.getFeature(FEATURE_SAX_INPUT);
reporter.check(bit, true,
"getFeature(" + FEATURE_SAX_INPUT
+ ") must be true for Xalan 2.x");
}
catch (Exception e)
{
reporter.checkFail("getFeature(" + FEATURE_SAX_INPUT
+ ") threw: " + e.toString());
}
// TODO investigate why setting this feature false throws SAXNotRecognizedException
// Maybe we can't set the native features?
// p.setFeature(FEATURE_SAX_INPUT, false);
// Test errorHandler set/get api and functionality
LoggingSAXErrorHandler errHandler =
new LoggingSAXErrorHandler(reporter);
errHandler.setThrowWhen(errHandler.THROW_ON_FATAL);
p.setErrorHandler(errHandler);
reporter.checkObject(p.getErrorHandler(), errHandler,
"set/getErrorHandler API test");
// See if we can get the errHandler to have something output
try
{
Templates t = p.process(new InputSource(""));
}
catch (Exception e)
{
reporter.logStatusMsg("process(blank string) threw: "
+ e.toString());
}
reporter.logStatusMsg("process(blank string) errorHandler :"
+ errHandler.getLastError() + ": "
+ errHandler.getCounterString());
try
{
Templates t = p.process(new InputSource(INVALID_NAME));
}
catch (Exception e)
{
reporter.logStatusMsg("process(" + INVALID_NAME + ") threw: "
+ e.toString());
}
reporter.logStatusMsg("process(" + INVALID_NAME + ") errorHandler :"
+ errHandler.getLastError() + ": "
+ errHandler.getCounterString());
try
{
Templates t = p.process(new InputSource(simpleTest.inputName));
// TODO: cause an error parsing the XML or something
}
catch (Exception e)
{
reporter.logStatusMsg("process(" + simpleTest.inputName
+ ") threw: " + e.toString());
}
reporter.logStatusMsg("process(" + simpleTest.inputName
+ ") errorHandler :"
+ errHandler.getLastError() + ": "
+ errHandler.getCounterString());
// Cheap set/get test for EntityResolver
LoggingEntityResolver entRes = new LoggingEntityResolver(reporter);
p.setEntityResolver(entRes);
reporter.checkObject(p.getEntityResolver(), entRes,
"set/getEntityResolver API test");
reporter.checkAmbiguous(
"// TODO add validation for set/getEntityResolver");
LoggingURIResolver URIRes = new LoggingURIResolver(reporter);
p.setURIResolver(URIRes);
reporter.checkObject(p.getURIResolver(), URIRes,
"set/getURIResolver API test");
reporter.checkAmbiguous(
"// TODO add validation for set/getURIResolver");
try
{
XMLReader reader = XMLReaderFactory.createXMLReader();
p.setXMLReader(reader);
reporter.checkObject(p.getXMLReader(), reader,
"set/getXMLReader API test");
reporter.checkAmbiguous(
"// TODO add validation for set/getXMLReader");
}
catch (SAXException se)
{
reporter.checkErr("set/getXMLReader API test: " + se.toString());
reporter.logThrowable(reporter.STATUSMSG, se,
"set/getXMLReader API test threw:");
}
reporter.testCaseClose();
return true;
}
/**
* TRAX Processor: cover process* instance methods.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase3()
{
reporter.testCaseInit(
"TRAX Processor: cover process* instance methods");
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
Processor p = null;
try
{
p = Processor.newInstance(XSLT);
if (p == null)
{
reporter.checkFail(
"Processor is null; cannot continue testcase");
return false;
}
}
catch (ProcessorFactoryException pfe)
{ // No-op
}
// Processor.process() basic coverage test
String messageStylesheet = inputDir + File.separator + XAPI
+ File.separator
+ "ProcessorAPIMessage.xsl";
LoggingSAXErrorHandler errHandler;
errHandler = new LoggingSAXErrorHandler(reporter);
errHandler.setThrowWhen(errHandler.THROW_ON_FATAL);
try
{
p.setErrorHandler(errHandler);
Templates t = p.process(new InputSource(messageStylesheet));
reporter.check((t != null), true,
"Created basic Templates object");
Transformer f = t.newTransformer();
reporter.check((f != null), true,
"Created basic Transformer object");
f.transform(new InputSource(simpleTest.xmlName),
new Result(new FileWriter(outNames.nextName())));
reporter.check(((new File(outNames.currentName())).exists()),
true, "transform() created an output file");
reporter.logStatusMsg("messageStylesheet just created output:"
+ outNames.currentName());
}
catch (Exception e)
{
reporter.checkErr("process() basic test threw: " + e.toString());
reporter.logThrowable(reporter.STATUSMSG, e,
"process() basic test threw:");
}
reporter.logStatusMsg("process() basic test errorHandler :"
+ errHandler.getLastError() + ": "
+ errHandler.getCounterString());
// Templates = Processor.processFromNode(Node) basic coverage test
reporter.checkAmbiguous(
"// TODO processFromNode(Node) copy from TraxMinitest");
// Templates = Processor.processFromNode(Node, String) basic coverage test
// TODO create stylesheet where String systemID is important
// (does this need an import or include, or does other basic stuff matter?)
reporter.checkAmbiguous(
"// TODO processFromNode(Node, String) test needs stylesheet written");
// Templates = Processor.processMultiple(InputSource[]) basic coverage test
// InputSource[] = Processor.getAssociatedStylesheets(InputSource, media, title, charset) basic coverage test
reporter.checkAmbiguous(
"// TODO getAssociatedStylesheets test needs stylesheet written");
// TemplatesBuilder = Processor.getTemplatesBuilder() basic coverage test
reporter.checkAmbiguous("// TODO getTemplatesBuilder() ");
reporter.testCaseClose();
return true;
}
/**
* Basic negative tests: various illegal stylesheets, etc..
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase4()
{
reporter.testCaseInit(
"Basic negative tests: various illegal stylesheets, etc.");
// Set the default, but leave the system property alone
// In theory, you could manually set the system property to some other
// TRAX-conformant processor, and we'd test that instead of Xalan 2.x
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
// Some invalid stylesheets to test for parsing/processing errors
// use simpleTest.xmlName as an XML file without a xsl:stylesheet element
Processor p = null;
LoggingSAXErrorHandler errHandler;
errHandler = new LoggingSAXErrorHandler(reporter);
errHandler.setThrowWhen(errHandler.THROW_ON_FATAL);
try
{
p = Processor.newInstance(XSLT);
p.setErrorHandler(errHandler);
Templates t = p.process(new InputSource(simpleTest.xmlName));
}
catch (Exception e)
{
reporter.logThrowable(reporter.ERRORMSG, e,
"process of an xmlFile threw:");
}
String basePath = outputDir + File.separator + XAPI + File.separator;
String illegalStylesheets[][] =
{
{ basePath + "badXMLData.xsl", "This is not your parents XML!" },
{ basePath + "badClosingTag.xsl",
"<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" },
{ basePath + "badNamespace.xsl",
"<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/blah/blah/blah\" version=\"1.0\">\n</xsl:stylesheet>" },
/**
* // For some reason, this still produces output
*
* {
* basePath + "badVersion.xsl",
* "<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"abc\">\n</xsl:stylesheet>"
* },
*/
{ basePath + "badTag.xsl",
"<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n<xsl:bad-tag/></xsl:stylesheet>" },
{ basePath + "badEntity.xsl",
"<?xml version=\"1.0\"?>\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999XSL/Transform\" version=\"1.0\">\n¬-an-entity;</xsl:stylesheet>" }
};
// Cheap-o validation; should be improved to validate each case separately
int numErrs = 0;
for (int i = 0; i < illegalStylesheets.length; i++)
{
if (!writeFile(illegalStylesheets[i][0],
illegalStylesheets[i][1]))
continue;
errHandler = new LoggingSAXErrorHandler(reporter);
errHandler.setThrowWhen(errHandler.THROW_ON_FATAL);
String tmp = "(0)"; // Marker for when exception is thrown
reporter.logTraceMsg("about to process: "
+ illegalStylesheets[i][0]);
try
{
p = Processor.newInstance(XSLT);
// Should we actually expect anything to get passed to the errHandler?
p.setErrorHandler(errHandler);
tmp = "(1)";
Templates t =
p.process(new InputSource(illegalStylesheets[i][0]));
tmp = "(2)";
Transformer f = t.newTransformer();
tmp = "(3)";
f.transform(new InputSource(simpleTest.xmlName),
new Result(new FileWriter(outNames.nextName())));
reporter.checkFail(illegalStylesheets[i][0]
+ " should not have created output:"
+ outNames.currentName());
}
catch (Exception e)
{
reporter.logThrowable(reporter.ERRORMSG, e,
"process" + tmp + " of "
+ illegalStylesheets[i][0] + " threw:");
numErrs++;
}
reporter.logStatusMsg("process(" + tmp + " of "
+ illegalStylesheets[i][0] + "):"
+ errHandler.getLastError() + ": "
+ errHandler.getCounterString());
} // end of for...
reporter.check((numErrs > 0), true,
"Some bad stylesheets correctly threw exceptions");
reporter.testCaseClose();
return true;
}
/**
* Cheap-o utility to write a test file; no validation performed.
*
* NEEDSDOC @param fileName
* NEEDSDOC @param contents
*
* NEEDSDOC ($objectName$) @return
*/
public boolean writeFile(String fileName, String contents)
{
reporter.logTraceMsg("writeFile(" + fileName + ",...)");
try
{
FileWriter fw = new FileWriter(fileName);
fw.write(contents);
fw.close();
return true;
}
catch (IOException ioe)
{
reporter.logThrowable(reporter.ERRORMSG, ioe, "writeFile threw:");
return false;
}
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by ProcessorAPITest:\n"
+ "(Note: assumes inputDir=.\\prod)\n"
+ "-processorClassname classname.of.processor (to override setPlatformDefaultProcessor to Xalan 2.x)\n"
+ super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
ProcessorAPITest app = new ProcessorAPITest();
app.doMain(args);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/ResultAPITest.java
Index: ResultAPITest.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/>.
*/
/*
*
* ResultAPITest.java
*
*/
package org.apache.qetest.trax;
import org.apache.qetest.*;
import org.apache.qetest.xsl.*;
// Just import the whole trax package; note the packaging is likely to change
import org.apache.trax.*;
// Use Serializer classes from Xalan distro
import org.apache.serialize.OutputFormat;
import org.apache.serialize.Serializer;
import org.apache.serialize.SerializerFactory;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.Parser;
import org.xml.sax.ContentHandler;
// Needed DOM classes
import org.w3c.dom.Node;
import org.w3c.dom.Document;
// javax JAXP classes for parser pluggability
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
// java classes
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Properties;
//-------------------------------------------------------------------------
/**
* Basic API coverage test for the Result class of TRAX.
* @author shane_curcuru@lotus.com
*/
public class ResultAPITest extends XSLProcessorTestBase
{
/**
* Cheap-o filename for various output files.
*
*/
protected OutputNameManager outNames;
/** Cheap-o filename set for both API tests and exampleSimple. */
protected XSLTestfileInfo simpleTest = new XSLTestfileInfo();
/** Cache the relevant system property. */
protected String saveXSLTProp = null;
/** Allow user to override our default of Xalan 2.x processor classname. */
public static final String XALAN_CLASSNAME =
"org.apache.xalan.processor.StylesheetProcessor";
/** NEEDSDOC Field PROCESSOR_CLASSNAME */
protected String PROCESSOR_CLASSNAME = "processorClassname";
/** NEEDSDOC Field processorClassname */
protected String processorClassname = XALAN_CLASSNAME;
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = "trax.processor.xslt";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
/** NEEDSDOC Field PROPERTY_LEXICAL_HANDLER */
public static final String PROPERTY_LEXICAL_HANDLER =
"http://xml.org/sax/properties/lexical-handler";
/** NEEDSDOC Field FEATURE_DOM_INPUT */
public static final String FEATURE_DOM_INPUT =
"http://xml.org/trax/features/dom/input";
/** NEEDSDOC Field FEATURE_SAX_INPUT */
public static final String FEATURE_SAX_INPUT =
"http://xml.org/trax/features/sax/input";
/** NEEDSDOC Field XAPI */
public static final String XAPI = "trax";
/** Default ctor initializes test name, comment, numTestCases. */
public ResultAPITest()
{
numTestCases = 2; // REPLACE_num
testName = "ResultAPITest";
testComment = "Basic API coverage test for the Result class of TRAX";
}
/**
* Initialize this test - Set names of xml/xsl test files, cache system property.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Used for all tests; just dump files in xapi subdir
File outSubDir = new File(outputDir + File.separator + XAPI);
if (!outSubDir.mkdirs())
reporter.logWarningMsg("Could not create output dir: "
+ outSubDir);
outNames = new OutputNameManager(outputDir + File.separator + XAPI
+ File.separator + testName, ".out");
// Used for API coverage and exampleSimple
String testBasePath = inputDir + File.separator + XAPI
+ File.separator;
String goldBasePath = goldDir + File.separator + XAPI
+ File.separator;
simpleTest.xmlName = testBasePath + "APIMinitest.xml";
simpleTest.inputName = testBasePath + "APIMinitest.xsl";
simpleTest.goldName = goldBasePath + "APIMinitest.out";
// Cache trax system property
saveXSLTProp = System.getProperty(TRAX_PROCESSOR_XSLT);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ saveXSLTProp);
// Check if user wants to use a processor other than Xalan 2.x
processorClassname = testProps.getProperty(PROCESSOR_CLASSNAME,
XALAN_CLASSNAME);
reporter.logInfoMsg(PROCESSOR_CLASSNAME + " property is: "
+ processorClassname);
return true;
}
/**
* Cleanup this test - reset the cached system property trax.processor.xslt.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileClose(Properties p)
{
if (saveXSLTProp == null)
{
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
}
else
{
System.getProperties().put(TRAX_PROCESSOR_XSLT, saveXSLTProp);
}
return true;
}
/**
* TRAX Result: cover APIs.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase1()
{
reporter.testCaseInit("TRAX Result: cover APIs");
// Ctor(OutputStream)
// set/getByteStream (OutputStream)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Result resultBytes = new Result(baos);
reporter.checkObject(resultBytes.getByteStream(), baos,
"ctor()/getByteStream()");
// Verify other items are not set
if ((resultBytes.getCharacterStream() == null)
&& (resultBytes.getNode() == null))
{
reporter.checkPass("resultBytes should not have Writer/Node");
}
else
{
reporter.checkFail("resultBytes should not have Writer/Node");
}
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
resultBytes.setByteStream(baos2);
reporter.checkObject(resultBytes.getByteStream(), baos2,
"set/getByteStream()");
// Ctor(Writer)
// set/getCharacterStream (Writer)
StringWriter sw = new StringWriter();
Result resultWriter = new Result(sw);
reporter.checkObject(resultWriter.getCharacterStream(), sw,
"ctor()/getCharacterStream()");
// Verify other items are not set
if ((resultWriter.getByteStream() == null)
&& (resultWriter.getNode() == null))
{
reporter.checkPass(
"resultWriter should not have ByteStream/Node");
}
else
{
reporter.checkFail(
"resultWriter should not have ByteStream/Node");
}
StringWriter sw2 = new StringWriter();
resultWriter.setCharacterStream(sw2);
reporter.checkObject(resultWriter.getCharacterStream(), sw2,
"set/getCharacterStream()");
// Ctor(Node)
// set/getNode (Node)
// What's the easiest way to just create a Node?
try
{
DocumentBuilderFactory dfactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
Node n = docBuilder.newDocument();
Result resultNode = new Result(n);
reporter.checkObject(resultNode.getNode(), n, "ctor()/getNode()");
// Verify other items are not set
if ((resultNode.getByteStream() == null)
&& (resultNode.getCharacterStream() == null))
{
reporter.checkPass(
"resultNode should not have ByteStream/CharacterStream");
}
else
{
reporter.checkFail(
"resultNode should not have ByteStream/CharacterStream");
}
Node n2 = docBuilder.newDocument();
resultNode.setNode(n2);
reporter.checkObject(resultNode.getNode(), n2, "set/getNode()");
}
catch (ParserConfigurationException pce)
{
reporter.checkFail("Creating Node threw: " + pce.toString());
reporter.logThrowable(reporter.ERRORMSG, pce,
"Creating Node threw:");
}
reporter.testCaseClose();
return true;
}
/**
* TRAX Result: validate basic Result functionality.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase2()
{
reporter.testCaseInit(
"TRAX Result: validate basic Results functionality");
// Actually use each type of Results to get some output
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
// Setup inputs and get a stylesheet for use by all tests
InputSource xsl = new InputSource(simpleTest.inputName);
InputSource xml = new InputSource(simpleTest.xmlName);
Templates templates = null;
Transformer transformer = null;
try
{
Processor p = Processor.newInstance(XSLT);
// Setup inputs and get a stylesheet for use by all tests
templates = p.process(xsl);
}
catch (Exception e)
{
reporter.checkFail(
"Problem creating Templates; cannot continue testcase");
reporter.logThrowable(reporter.ERRORMSG, e,
"Problem creating Templates");
return true;
}
try
{
// Test Results(ByteStream)
FileOutputStream fos = new FileOutputStream(outNames.nextName());
Result resultBytes = new Result(fos);
transformer = templates.newTransformer();
transformer.transform(xml, resultBytes);
// Ensure the stream is flushed and closed
fos.close();
fileChecker.check(reporter, new File(outNames.currentName()),
new File(simpleTest.goldName),
"Result(ByteStream) into "
+ outNames.currentName());
}
catch (Exception e)
{
reporter.checkFail("Testing Results(ByteStream) threw: "
+ e.toString());
reporter.logThrowable(reporter.ERRORMSG, e,
"Testing Results(ByteStream) threw:");
}
try
{
// Test Results(CharacterStream)
FileWriter fw = new FileWriter(outNames.nextName());
Result resultWriter = new Result(fw);
transformer = templates.newTransformer();
transformer.transform(xml, resultWriter);
// Ensure the stream is flushed and closed
fw.close();
fileChecker.check(reporter, new File(outNames.currentName()),
new File(simpleTest.goldName),
"Result(CharacterStream) into "
+ outNames.currentName());
}
catch (Exception e)
{
reporter.checkFail("Testing Results(CharacterStream) threw: "
+ e.toString());
reporter.logThrowable(reporter.ERRORMSG, e,
"Testing Results(CharacterStream) threw:");
}
try
{
// Test Result(Node)
DocumentBuilderFactory dfactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
Document node = docBuilder.newDocument();
Result resultNode = new Result(node);
transformer = templates.newTransformer();
transformer.transform(xml, resultNode);
// Use the serializers to output the result to disk
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(
new FileOutputStream(outNames.nextName()));
serializer.asDOMSerializer().serialize(node);
fileChecker.check(reporter, new File(outNames.currentName()),
new File(simpleTest.goldName),
"Result(Node) into " + outNames.currentName());
}
catch (Exception e)
{
reporter.checkFail("Testing Results(Node) threw: "
+ e.toString());
reporter.logThrowable(reporter.ERRORMSG, e,
"Testing Results(Node) threw:");
}
reporter.testCaseClose();
return true;
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by ResultAPITest:\n"
+ "(Note: assumes inputDir=.\\prod)\n"
+ "-processorClassname classname.of.processor (to override setPlatformDefaultProcessor to Xalan 2.x)\n"
+ super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
ResultAPITest app = new ResultAPITest();
app.doMain(args);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/TemplatesAPITest.java
Index: TemplatesAPITest.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/>.
*/
/*
*
* TemplatesAPITest.java
*
*/
package org.apache.qetest.trax;
import org.apache.qetest.*;
import org.apache.qetest.xsl.*;
// Just import the whole trax package; note the packaging is likely to change
import org.apache.trax.*;
// Use Serializer classes from Xalan distro
import org.apache.serialize.Method;
import org.apache.serialize.OutputFormat;
import org.apache.serialize.Serializer;
import org.apache.serialize.SerializerFactory;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.Parser;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.XMLReader;
// Needed DOM classes
import org.w3c.dom.Node;
import org.w3c.dom.Document;
// javax JAXP classes for parser pluggability
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
// java classes
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Properties;
//-------------------------------------------------------------------------
/**
* Basic API coverage test for the Templates and TemplatesBuilder classes of TRAX.
* @author shane_curcuru@lotus.com
*/
public class TemplatesAPITest extends XSLProcessorTestBase
{
/**
* Cheap-o filename for various output files.
*
*/
protected OutputNameManager outNames;
/** Cheap-o filename set for both API tests and exampleSimple. */
protected XSLTestfileInfo simpleTest = new XSLTestfileInfo();
/** Name of a stylesheet with xsl:output HTML. */
protected String htmlStylesheet = null;
/** Cache the relevant system property. */
protected String saveXSLTProp = null;
/** Allow user to override our default of Xalan 2.x processor classname. */
public static final String XALAN_CLASSNAME =
"org.apache.xalan.processor.StylesheetProcessor";
/** NEEDSDOC Field PROCESSOR_CLASSNAME */
protected String PROCESSOR_CLASSNAME = "processorClassname";
/** NEEDSDOC Field processorClassname */
protected String processorClassname = XALAN_CLASSNAME;
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = "trax.processor.xslt";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
// http://xml.org/sax/features/namespace-prefixes feature
// http://xml.org/sax/features/namespaces feature
// http://xml.org/sax/features/external-general-entities property
// http://xml.org/sax/features/external-parameter-entities property
// http://xml.apache.org/xslt/sourcebase property in TransformerImpl
/** NEEDSDOC Field PROPERTY_LEXICAL_HANDLER */
public static final String PROPERTY_LEXICAL_HANDLER =
"http://xml.org/sax/properties/lexical-handler";
/** NEEDSDOC Field FEATURE_DOM_INPUT */
public static final String FEATURE_DOM_INPUT =
"http://xml.org/trax/features/dom/input";
/** NEEDSDOC Field FEATURE_SAX_INPUT */
public static final String FEATURE_SAX_INPUT =
"http://xml.org/trax/features/sax/input";
/** NEEDSDOC Field XAPI */
public static final String XAPI = "trax";
/** Default ctor initializes test name, comment, numTestCases. */
public TemplatesAPITest()
{
numTestCases = 2; // REPLACE_num
testName = "TemplatesAPITest";
testComment =
"Basic API coverage test for the Templates and TemplatesBuilder classes of TRAX";
}
/**
* Initialize this test - Set names of xml/xsl test files, cache system property.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Used for all tests; just dump files in xapi subdir
File outSubDir = new File(outputDir + File.separator + XAPI);
if (!outSubDir.mkdirs())
reporter.logWarningMsg("Could not create output dir: "
+ outSubDir);
outNames = new OutputNameManager(outputDir + File.separator + XAPI
+ File.separator + testName, ".out");
// Used for API coverage and exampleSimple
String testBasePath = inputDir + File.separator + XAPI
+ File.separator;
String goldBasePath = goldDir + File.separator + XAPI
+ File.separator;
simpleTest.xmlName = testBasePath + "APIMinitest.xml";
simpleTest.inputName = testBasePath + "APIMinitest.xsl";
simpleTest.goldName = goldBasePath + "APIMinitest.out";
htmlStylesheet = inputDir + File.separator + XAPI + File.separator
+ "TemplatesAPIHTML.xsl";
// Cache trax system property
saveXSLTProp = System.getProperty(TRAX_PROCESSOR_XSLT);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ saveXSLTProp);
// Check if user wants to use a processor other than Xalan 2.x
processorClassname = testProps.getProperty(PROCESSOR_CLASSNAME,
XALAN_CLASSNAME);
reporter.logInfoMsg(PROCESSOR_CLASSNAME + " property is: "
+ processorClassname);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
// Just call this static method once for the whole test
// TODO will this ever affect other tests run through a harness?
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
return true;
}
/**
* Cleanup this test - reset the cached system property trax.processor.xslt.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileClose(Properties p)
{
if (saveXSLTProp == null)
{
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
}
else
{
System.getProperties().put(TRAX_PROCESSOR_XSLT, saveXSLTProp);
}
return true;
}
/**
* TRAX Templates: cover APIs and functionality.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase1()
{
reporter.testCaseInit("TRAX Templates: cover APIs and functionality");
Processor p = null;
try
{
p = Processor.newInstance(XSLT);
}
catch (Exception e)
{
reporter.checkFail(
"Problem creating Processor; cannot continue testcase");
reporter.logThrowable(reporter.ERRORMSG, e,
"Problem creating Processor");
return true;
}
try
{
// Cover APIs newTransformer(), getOutputFormat()
Templates templates =
p.process(new InputSource(simpleTest.inputName));
Transformer transformer = templates.newTransformer();
reporter.check((transformer != null), true,
"newTransformer() is non-null for "
+ simpleTest.inputName);
OutputFormat outputFormat = templates.getOutputFormat();
reporter.check((outputFormat != null), true,
"getOutputFormat() is non-null for "
+ simpleTest.inputName);
reporter.check(outputFormat.getMethod(), Method.XML,
"outputFormat.getMethod() is xml for "
+ simpleTest.inputName);
}
catch (Exception e)
{
reporter.checkErr("newTransformer/getOutputFormat threw: "
+ e.toString());
reporter.logThrowable(reporter.STATUSMSG, e,
"newTransformer/getOutputFormat threw:");
}
try
{
Templates templatesHTML =
p.process(new InputSource(htmlStylesheet));
OutputFormat outputFormatHTML = templatesHTML.getOutputFormat();
reporter.check(outputFormatHTML.getMethod(), Method.HTML,
"outputFormat() is html for " + htmlStylesheet);
}
catch (Exception e)
{
reporter.checkErr("outputFormat() is html... threw: "
+ e.toString());
reporter.logThrowable(reporter.STATUSMSG, e,
"outputFormat() is html... threw:");
}
reporter.testCaseClose();
return true;
}
/**
* TRAX TemplatesBuilder: cover APIs and functionality.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase2()
{
reporter.testCaseInit(
"TRAX TemplatesBuilder: cover APIs and functionality");
try
{
Processor p = Processor.newInstance(XSLT);
TemplatesBuilder templatesBuilder = p.getTemplatesBuilder();
reporter.check((templatesBuilder != null), true,
"getTemplatesBuilder() is non-null");
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(templatesBuilder);
if (templatesBuilder instanceof org.xml.sax.ext.LexicalHandler)
{
reader.setProperty(PROPERTY_LEXICAL_HANDLER,
templatesBuilder);
}
reader.parse(new InputSource(htmlStylesheet));
Templates templates = templatesBuilder.getTemplates();
reporter.check((templates != null), true,
"templates from SAX build is non-null");
// Cheap-o verification it's the right stylesheet
OutputFormat outputFormatHTML = templates.getOutputFormat();
reporter.check(outputFormatHTML.getMethod(), Method.HTML,
"outputFormat() is html for " + htmlStylesheet);
reporter.checkAmbiguous(
"//TODO create stylesheet both ways (t=process() and via SAX build) and compare outputs");
reporter.checkAmbiguous(
"//TODO setBaseID() and then create different stylesheet");
}
catch (Exception e)
{
reporter.checkFail("TestCase threw: " + e.toString());
reporter.logThrowable(reporter.ERRORMSG, e, "TestCase threw:");
return true;
}
reporter.testCaseClose();
return true;
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by TemplatesAPITest:\n"
+ "(Note: assumes inputDir=.\\prod)\n"
+ "-processorClassname classname.of.processor (to override setPlatformDefaultProcessor to Xalan 2.x)\n"
+ super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
TemplatesAPITest app = new TemplatesAPITest();
app.doMain(args);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/TestThreads.java
Index: TestThreads.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/>.
*/
/*
*
* TestThreads.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;
// For optional URI/URLs instead of string filenames
import java.net.URL;
import java.net.MalformedURLException;
// Note that not all imports are listed here
import org.apache.trax.*; // TRAX package name will change
//-------------------------------------------------------------------------
/**
* Testing multiple simultaneous processors on different threads 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>
* @author shane_curcuru@lotus.com
*/
public class TestThreads
{
/**
* Convenience method to print out usage information.
*
* NEEDSDOC ($objectName$) @return
*/
public static String usage()
{
return ("Usage: TestThreads file.properties :\n"
+ " where the properties file can set:,\n"
+ " testDir=e:\\builds\\xsl-test\n"
+ " outDir=e:\\builds\\xsl-test\\results\n"
+ " logFile=e:\\builds\\xsl-test\\results\\TestThreads.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;
/** NEEDSDOC Field numRunnerCalls */
protected int numRunnerCalls = 50;
/**
* Root input filenames that certain runners should use, in the testDir.
* <p>'setOneFile=File'; 'setTwoFile=File'; 'setThreeFile=File'
* in .prop file to set; default is TestThreads1, TestThreads2, TestThreads3.</p>
* <p>Files are found in 'testDir=c:\bar\baz' from .prop file.</p>
*/
protected String testDir = null;
/** NEEDSDOC Field setOneFilenameRoot */
protected String setOneFilenameRoot = "TestThreads1";
/** NEEDSDOC Field setTwoFilenameRoot */
protected String setTwoFilenameRoot = "TestThreads2";
/** NEEDSDOC Field setThreeFilenameRoot */
protected String setThreeFilenameRoot = "TestThreads3";
/**
* All output logs and files get put in the outDir.
*/
protected String outDir = 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
/** NEEDSDOC Field ID */
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;
/** NEEDSDOC Field FUTUREUSE */
public static final int FUTUREUSE = 8;
/**
* Name of main file's output logging; each runner also has separate output.
*/
protected String logFileName = "TestThreads.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 fileName=\"" + 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(testDir + setOneFilenameRoot + ".xsl",
null).toExternalForm();
String setTwoURL =
getURLFromString(testDir + setTwoFilenameRoot + ".xsl",
null).toExternalForm();
String setThreeURL =
getURLFromString(testDir + setThreeFilenameRoot + ".xsl",
null).toExternalForm();
Processor stylesheetProcessor = Processor.newInstance("xslt");
errStr = "Processing stylesheet1 threw: ";
stylesheet1 =
stylesheetProcessor.process(new InputSource(setOneURL));
errStr = "Processing stylesheet2 threw: ";
stylesheet2 =
stylesheetProcessor.process(new InputSource(setTwoURL));
errStr = "Processing stylesheet3 threw: ";
stylesheet3 =
stylesheetProcessor.process(new InputSource(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++)
{
TestThreadsRunner r1, r2, r3;
Thread t1, t2, t3;
// First set of runners reports on memory usage periodically
rValues[ID] = "one-" + i;
rValues[XMLNAME] = "file:" + testDir + setOneFilenameRoot
+ ".xml";
rValues[XSLNAME] = testDir + setOneFilenameRoot + ".xsl";
rValues[OUTNAME] = outDir + setOneFilenameRoot + "r" + i;
rValues[PARAMNAME] = paramName;
rValues[PARAMVAL] = paramVal;
rValues[OPTIONS] = "memory;param";
errStr = "Creating runnerone-" + i + " threw: ";
r1 = new TestThreadsRunner(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:" + testDir + setTwoFilenameRoot
+ ".xml";
rValues[XSLNAME] = testDir + setTwoFilenameRoot + ".xsl";
rValues[OUTNAME] = outDir + setTwoFilenameRoot + "r" + i;
rValues[PARAMNAME] = paramName;
rValues[PARAMVAL] = paramVal;
rValues[OPTIONS] = "polite;param";
if ((liaison != null) &&!(liaison.equals("")))
rValues[LIAISON] = liaison;
errStr = "Creating runnertwo-" + i + " threw: ";
r2 = new TestThreadsRunner(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:" + testDir + setThreeFilenameRoot
+ ".xml";
rValues[XSLNAME] = testDir + setThreeFilenameRoot + ".xsl";
rValues[OUTNAME] = outDir + setThreeFilenameRoot + "r" + i;
rValues[PARAMNAME] = paramName;
rValues[PARAMVAL] = paramVal;
rValues[OPTIONS] = "recreate;memory";
errStr = "Creating runnerthree-" + i + " threw: ";
r3 = new TestThreadsRunner(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=\"TestThreads main thread now complete\"/>");
println("</resultsfile>");
if (pWriter != null)
pWriter.flush();
}
/**
* Read in properties file and set instance variables.
*
* NEEDSDOC @param fName
*
* NEEDSDOC ($objectName$) @return
*/
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
outDir = p.getProperty("outputDir", outDir);
// Validate the outDir and use it to reset the logFileName
File oDir = new File(outDir);
if (!oDir.exists())
{
if (!oDir.mkdirs())
{
// Error, we can't create the outDir, default to current dir
println("<message desc=\"outputDir(" + outDir
+ ") does not exist, defaulting to .\"/>");
outDir = ".";
}
}
// Verify testDir as well
testDir = p.getProperty("inputDir", testDir);
File tDir = new File(testDir);
if (!tDir.exists())
{
if (!tDir.mkdirs())
{
// Error, we can't create the testDir, abort
println("<message desc=\"inputDir(" + testDir
+ ") does not exist, terminating test\"/>");
return false;
}
}
// Add on separators
testDir += File.separator;
outDir += 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
}
TestThreads app = new TestThreads();
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.
*
* 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 TestThreads
/**
* 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 TestThreadsRunner 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
/**
* Constructor TestThreadsRunner
*
*
* NEEDSDOC @param params
* NEEDSDOC @param xslStylesheet
* NEEDSDOC @param numProcesses
*/
TestThreadsRunner(String[] params, Templates xslStylesheet,
int numProcesses)
{
this.xslStylesheet = xslStylesheet;
this.numProcesses = numProcesses;
this.runnerID = params[TestThreads.ID];
this.xmlName = params[TestThreads.XMLNAME];
this.xslName = params[TestThreads.XSLNAME];
this.outName = params[TestThreads.OUTNAME];
this.paramName = params[TestThreads.PARAMNAME];
this.paramVal = params[TestThreads.PARAMVAL];
if (params[TestThreads.OPTIONS].indexOf("polite") > 0)
polite = true;
if (params[TestThreads.OPTIONS].indexOf("recreate") > 0)
recreate = true;
if (params[TestThreads.OPTIONS].indexOf("validate") > 0)
validate = true;
if (params[TestThreads.OPTIONS].indexOf("memory") > 0)
reportMem = true;
if (params[TestThreads.OPTIONS].indexOf("param") > 0)
setParam = true;
if (params[TestThreads.LIAISON] != null) // TRAX unused
liaison = params[TestThreads.LIAISON];
}
/**
* 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 + "\">");
Processor p = null;
try
{
// Each runner creates it's own processor for use and it's own error log
p = Processor.newInstance("xslt");
// Munge the input filenames to be URLs
xmlName = TestThreads.getURLFromString(xmlName,
null).toExternalForm();
xslName = TestThreads.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();
FileOutputStream resultStream1 =
new FileOutputStream(outName + ".out");
Result result1 = new Result(resultStream1);
if (setParam)
transformer1.setParameter(paramName, null, paramVal);
print("."); // Note presence of this in logs shows which process threw an exception
transformer1.transform(new InputSource(xmlName), result1);
resultStream1.close();
// Temporary vars go out of scope for cleanup here
}
// Now process something with a newly-processed stylesheet
{
Templates templates2 =
p.process(new InputSource(xslName));
Transformer transformer2 = templates2.newTransformer();
FileOutputStream resultStream2 =
new FileOutputStream(outName + "_.out");
Result result2 = new Result(resultStream2);
if (setParam)
transformer2.setParameter(paramName, null, paramVal);
print("*"); // Note presence of this in logs shows which process threw an exception
transformer2.transform(new InputSource(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 (TransformException te)
{
println("\n<transformexception desc=\"" + te.toString() + "\">");
logStackTrace(te, errWriter);
logContainedException(te, errWriter);
println("</transformexception>");
println("</arbitrary>");
println("<message desc=\"" + runnerID + ":complete-ERROR:after:"
+ i + "\"/>");
}
catch (SAXException se)
{
println("\n<saxexception desc=\"" + se.toString() + "\">");
logStackTrace(se, errWriter);
logContainedException(se, errWriter);
println("</saxexception>");
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()...
/**
* NEEDSDOC Method logContainedException
*
*
* NEEDSDOC @param parent
* NEEDSDOC @param p
*/
private void logContainedException(SAXException 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 TestThreadsRunner...
// END OF FILE
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/TransformerAPITest.java
Index: TransformerAPITest.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/>.
*/
/*
*
* TransformerAPITest.java
*
*/
package org.apache.qetest.trax;
import org.apache.qetest.*;
import org.apache.qetest.xsl.*;
// Just import the whole trax package; note the packaging is likely to change
import org.apache.trax.*;
// Use Serializer classes from Xalan distro
import org.apache.serialize.Method;
import org.apache.serialize.OutputFormat;
// java classes
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.Parser;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.XMLReader;
// Needed DOM classes
import org.w3c.dom.Node;
import org.w3c.dom.Document;
// javax JAXP classes for parser pluggability
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
//-------------------------------------------------------------------------
/**
* Basic API coverage test for the Transformer class of TRAX.
* @author shane_curcuru@lotus.com
*/
public class TransformerAPITest extends XSLProcessorTestBase
{
/**
* Cheap-o filename for various output files.
*
*/
protected OutputNameManager outNames;
/** Cheap-o filename set for both API tests and exampleSimple. */
protected XSLTestfileInfo simpleTest = new XSLTestfileInfo();
/** NEEDSDOC Field paramTest */
protected XSLTestfileInfo paramTest = new XSLTestfileInfo();
/** Cache the relevant system property. */
protected String saveXSLTProp = null;
/** Allow user to override our default of Xalan 2.x processor classname. */
public static final String XALAN_CLASSNAME =
"org.apache.xalan.processor.StylesheetProcessor";
/** NEEDSDOC Field PROCESSOR_CLASSNAME */
protected String PROCESSOR_CLASSNAME = "processorClassname";
/** NEEDSDOC Field processorClassname */
protected String processorClassname = XALAN_CLASSNAME;
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = "trax.processor.xslt";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
/** NEEDSDOC Field PROPERTY_LEXICAL_HANDLER */
public static final String PROPERTY_LEXICAL_HANDLER =
"http://xml.org/sax/properties/lexical-handler";
/** NEEDSDOC Field FEATURE_DOM_INPUT */
public static final String FEATURE_DOM_INPUT =
"http://xml.org/trax/features/dom/input";
/** NEEDSDOC Field FEATURE_SAX_INPUT */
public static final String FEATURE_SAX_INPUT =
"http://xml.org/trax/features/sax/input";
/** NEEDSDOC Field XAPI */
public static final String XAPI = "trax";
/** Default ctor initializes test name, comment, numTestCases. */
public TransformerAPITest()
{
numTestCases = 2; // REPLACE_num
testName = "TransformerAPITest";
testComment = "Basic API coverage test for the class of TRAX";
}
/**
* Initialize this test - Set names of xml/xsl test files, cache system property.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Used for all tests; just dump files in xapi subdir
File outSubDir = new File(outputDir + File.separator + XAPI);
if (!outSubDir.mkdirs())
reporter.logWarningMsg("Could not create output dir: "
+ outSubDir);
outNames = new OutputNameManager(outputDir + File.separator + XAPI
+ File.separator + testName, ".out");
// Used for API coverage and exampleSimple
String testBasePath = inputDir + File.separator + XAPI
+ File.separator;
String goldBasePath = goldDir + File.separator + XAPI
+ File.separator;
simpleTest.xmlName = testBasePath + "APIMinitest.xml";
simpleTest.inputName = testBasePath + "APIMinitest.xsl";
simpleTest.goldName = goldBasePath + "APIMinitest.out";
paramTest.xmlName = testBasePath + "TraxMinitestParam.xml";
paramTest.inputName = testBasePath + "TraxMinitestParam.xsl";
paramTest.goldName = goldBasePath + "TraxMinitestParam.out";
// Cache trax system property
saveXSLTProp = System.getProperty(TRAX_PROCESSOR_XSLT);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ saveXSLTProp);
// Check if user wants to use a processor other than Xalan 2.x
processorClassname = testProps.getProperty(PROCESSOR_CLASSNAME,
XALAN_CLASSNAME);
reporter.logInfoMsg(PROCESSOR_CLASSNAME + " property is: "
+ processorClassname);
reporter.logInfoMsg(TRAX_PROCESSOR_XSLT + " property is: "
+ System.getProperty(TRAX_PROCESSOR_XSLT));
// Just call this static method once for the whole test
// TODO will this ever affect other tests run through a harness?
Processor.setPlatformDefaultProcessor(processorClassname);
reporter.logTraceMsg(
"Processor.setPlatformDefaultProcessor(processorClassname)");
return true;
}
/**
* Cleanup this test - reset the cached system property trax.processor.xslt.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileClose(Properties p)
{
if (saveXSLTProp == null)
{
System.getProperties().remove(TRAX_PROCESSOR_XSLT);
}
else
{
System.getProperties().put(TRAX_PROCESSOR_XSLT, saveXSLTProp);
}
return true;
}
/**
* TRAX Transformer: cover other APIs and functionality.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase1()
{
reporter.testCaseInit(
"TRAX Transformer: cover other APIs and functionality");
Processor p = null;
Templates templates = null;
try
{
p = Processor.newInstance(XSLT);
// Use paramTest for later testing of setParameter()/resetParameters()
templates = p.process(new InputSource(paramTest.inputName));
}
catch (Exception e)
{
reporter.checkFail(
"Problem creating Processor; cannot continue testcase");
reporter.logThrowable(reporter.ERRORMSG, e,
"Problem creating Processor");
return true;
}
Transformer transformer = templates.newTransformer();
try
{
// Cover APIs get*Handler()
if (p.getFeature(FEATURE_SAX_INPUT))
{
// Validate simply by checking for null
reporter.check((transformer.getInputContentHandler() != null),
true, "getInputContentHandler() is non-null");
reporter.check((transformer.getInputDeclHandler() != null),
true, "getInputDeclHandler() is non-null");
reporter.check((transformer.getInputLexicalHandler() != null),
true, "getInputLexicalHandler() is non-null");
}
else
{
// Can't validate, just print out values
reporter.logWarningMsg(
"getInputContentHandler is: "
+ transformer.getInputContentHandler());
reporter.logWarningMsg("getInputDeclHandler is: "
+ transformer.getInputDeclHandler());
reporter.logWarningMsg(
"getInputLexicalHandler is: "
+ transformer.getInputLexicalHandler());
}
}
catch (Exception e)
{
reporter.checkErr("get*Handler() test threw: " + e.toString());
reporter.logThrowable(reporter.ERRORMSG, e,
"get*Handler() test threw:");
}
try
{
transformer = templates.newTransformer();
// Basic setOutputFormat() test
String fName1 = outNames.nextName();
transformer.transform(new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(fName1)));
reporter.logStatusMsg("Created default output: " + fName1);
// Force output type to be different
OutputFormat outputFormat = templates.getOutputFormat();
outputFormat.setMethod(Method.Text); // TODO better switch
transformer.setOutputFormat(outputFormat);
transformer.transform(
new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(outNames.nextName())));
reporter.checkAmbiguous("// TODO validate: Created TEXT output: "
+ outNames.currentName());
}
catch (Exception e)
{
reporter.checkErr("setOutputFormat() test threw: "
+ e.toString());
reporter.logThrowable(reporter.ERRORMSG, e,
"setOutputFormat() test threw:");
}
try
{
transformer = templates.newTransformer();
// Basic setParameter()/resetParameters() test
String noParams = outNames.nextName();
String withParams = outNames.nextName();
String resetParams = outNames.nextName();
String neverParams = outNames.nextName();
transformer.transform(new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(noParams)));
reporter.logStatusMsg("Created noParams output: " + noParams);
String paramName = "paramName";
String paramNamespace = null; // TODO write stylesheet that uses the namespaces
String paramValue = "paramValue";
transformer.setParameter(paramName, paramNamespace, paramValue);
transformer.transform(
new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(withParams)));
reporter.logStatusMsg("Created withParams output: " + withParams);
transformer.resetParameters();
transformer.transform(
new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(resetParams)));
reporter.checkAmbiguous(
"// TODO validate Created resetParams output: "
+ resetParams);
// Also check what happens when you use a new transformer
transformer = templates.newTransformer();
transformer.transform(
new InputSource(paramTest.xmlName),
new Result(new FileOutputStream(neverParams)));
reporter.checkAmbiguous(
"// TODO validate Created neverParams output: "
+ neverParams);
}
catch (Exception e)
{
reporter.checkErr("setParameter()/resetParameters() test threw: "
+ e.toString());
reporter.logThrowable(
reporter.ERRORMSG, e,
"setParameter()/resetParameters() test threw:");
}
reporter.checkAmbiguous(
"// TODO Cover setURIResolver() API and functionality");
reporter.testCaseClose();
return true;
}
/**
* TRAX Transformer: cover transform*() APIs and functionality.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase2()
{
reporter.testCaseInit(
"TRAX Transformer: cover transform*() APIs and functionality");
try
{
Processor p = Processor.newInstance(XSLT);
// These tests are already covered in TraxWrapper.java
reporter.checkAmbiguous("// TODO transform(InputSource) -> SAX");
reporter.checkAmbiguous("// TODO transform(InputSource, Result)");
if (p.getFeature(FEATURE_DOM_INPUT))
{
reporter.checkAmbiguous(
"// TODO transformNode(Node, Result) if dom/input");
reporter.checkAmbiguous(
"// TODO transformNode(Node) -> SAX if dom/input");
}
else
{
reporter.logWarningMsg("Skipping transformNode(*) tests, "
+ FEATURE_DOM_INPUT
+ " not supported");
}
}
catch (Exception e)
{
reporter.checkFail("TestCase threw: " + e.toString());
reporter.logThrowable(reporter.ERRORMSG, e, "TestCase threw:");
return true;
}
reporter.testCaseClose();
return true;
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by TransformerAPITest:\n"
+ "(Note: assumes inputDir=.\\prod)\n"
+ "-processorClassname classname.of.processor (to override setPlatformDefaultProcessor to Xalan 2.x)\n"
+ super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
TransformerAPITest app = new TransformerAPITest();
app.doMain(args);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/trax/package.html
Index: package.html
===================================================================
<html>
<title>XSL-TEST TRAX testing package.</title>
<body>
<p>This package is for TRAX-interface API tests.<p>
<dl>
<dt><b>Author: </b></dt><dd><a href="mailto:shane_curcuru@lotus.com">Shane_Curcuru@lotus.com</a></dd>
<dt><b>Program(s) Under Test: </b></dt>
<dd><a href="http://xml.apache.org/xalan-j" target="_top">Xalan-J 2.x XSLT Processor</a></dd>
</dl>
<p>Most tests are completely generic to the TRAX interface, although they
do default System properties to use the Xalan-J 2.x implementation.<p>
<ul>Current tests are primarily focused on covering the API's and include:
<li>ProcessorAPITest - basic coverage of both factory methods and instance methods</li>
<li>ResultAPITest</li>
<li>TransformerAPITest</li>
<li>TemplatesAPITest - also covers TemplatesBuilder class</li>
<li>TestThreads - a semi-automated test for multithreaded testing,
results must be manually analyzed currently</li>
</ul>
</body>
</html>
1.1 xml-xalan/test/java/src/org/apache/qetest/xalanj1/ParamTest.java
Index: ParamTest.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/>.
*/
/*
*
* ParamTest.java
*
*/
package org.apache.qetest.xalanj1;
import org.apache.qetest.*;
import org.apache.qetest.xsl.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
// Specific imports for testing Xalan
import org.xml.sax.SAXException;
import org.apache.xalan.xslt.XSLTProcessor;
import org.apache.xalan.xslt.XSLTProcessorFactory;
import org.apache.xalan.xslt.XSLTInputSource;
import org.apache.xalan.xslt.XSLTResultTarget;
//-------------------------------------------------------------------------
/**
* Testing setStylesheetParam with XSL files.
*/
public class ParamTest extends XSLProcessorTestBase
{
/** Our version of the processor. */
protected org.apache.xalan.xslt.XSLTProcessor processor;
// Strings to hold names of our files
/** NEEDSDOC Field xmlFilename */
protected String xmlFilename;
/** NEEDSDOC Field xslFilename */
protected String xslFilename;
/** NEEDSDOC Field outNames */
protected OutputNameManager outNames;
/**
* Default constructor - initialize testName, Comment.
*/
public ParamTest()
{
numTestCases = 2; // REPLACE_num
testName = "ParamTest";
testComment = "Testing Xalan-J 1.x setStylesheetParam with XSL files";
}
/**
* Initialize this test - Update with your tests's data.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
outNames = new OutputNameManager(outputDir + File.separator
+ testName, ".out");
// inputDir should be parent of xapi directory
xmlFilename = inputDir + File.separator + "xalanj1" + File.separator
+ "ParamTest1.xml";
xslFilename = inputDir + File.separator + "xalanj1" + File.separator
+ "ParamTest1.xsl";
try
{
if ((liaison == null) || ("".equals(liaison)))
{
processor = XSLTProcessorFactory.getProcessor();
}
else
{
processor = XSLTProcessorFactory.getProcessorUsingLiaisonName(
liaison);
}
}
catch (Exception e)
{
reporter.checkFail("Could not create processor, threw: "
+ e.toString());
e.printStackTrace();
setAbortTest(true);
return false;
}
return true;
}
/**
* Write some test cases!
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase1()
{
reporter.testCaseInit("Testing setStylesheetParam");
try
{
org.apache.xalan.xslt.XSLTInputSource xmlSource =
new XSLTInputSource(xmlFilename);
org.apache.xalan.xslt.XSLTInputSource xslStylesheet =
new XSLTInputSource(xslFilename);
// Process the file as-is
org.apache.xalan.xslt.XSLTResultTarget xmlOutput1 =
new XSLTResultTarget(outNames.nextName());
processor.process(xmlSource, xslStylesheet, xmlOutput1);
processor.reset();
checkFileContains(outNames.currentName(), "ABC,<B>ABC</B>;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with default param value");
// Also verify that $t1 tests are correct
checkFileContains(
outNames.currentName(),
"<outt>true,false,false,false,notset</outt>",
"out(" + outNames.currentCounter()
+ ") ... also with default param value in select expr");
// Test setting the value and checking it in a select expr
processor.setStylesheetParam("t1", "''");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,true,false,false,</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr of a param blank string");
processor.setStylesheetParam("t1", "'a'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,true,false,a</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr of a param string");
processor.setStylesheetParam("t1", "'1'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,false,true,1</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr of a param number");
// Now re-set the value of the element-value params in the xsl file
processor.setStylesheetParam("p1", "'foo'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(), "foo,foo;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with literal param value");
// Test resetting the value of a parameter with the same processor instance
processor.setStylesheetParam("p1", "'bar'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(
outNames.currentName(), "bar,bar;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with replaced literal param value");
// Test putting other nodes in the value
processor.setStylesheetParam("p2",
"'<item>bar</item>'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(
outNames.currentName(),
"&lt;item&gt;bar&lt;/item&gt;,&lt;item&gt;bar&lt;/item&gt;;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with param value with nodes(?)");
// Param within a template
processor.setStylesheetParam("p3", "'foo3'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(
outNames.currentName(), "GHI,<B>GHI</B>;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with literal param value in a template, is not passed");
// Now test the value of the select-value params in the xsl file
processor.setStylesheetParam("s1", "'foos'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(), "foos,foos;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with literal param select");
processor.setStylesheetParam("s1", "'bars'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(
outNames.currentName(), "bars,bars;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with replaced literal param select");
processor.setStylesheetParam("s2", "'<item/>'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"&lt;item/&gt;,&lt;item/&gt;;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with nodes(?) param select");
processor.setStylesheetParam("s3", "'foos3'");
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(
outNames.currentName(), "s3val,s3val;",
"out(" + outNames.currentCounter()
+ ") Stylesheet with literal param select in a template, is not passed");
}
catch (Exception e)
{
reporter.logErrorMsg("Testcase threw: " + e.toString());
reporter.testCaseClose(); //- Required -
return false;
}
reporter.testCaseClose();
return true;
}
/**
* Write some test cases!
*
* NEEDSDOC ($objectName$) @return
*/
public boolean testCase2()
{
reporter.testCaseInit("Testing setStylesheetParam with XObjects");
try
{
// Note we may be implicitly using the same processor as before!
org.apache.xalan.xslt.XSLTInputSource xmlSource =
new XSLTInputSource(xmlFilename);
org.apache.xalan.xslt.XSLTInputSource xslStylesheet =
new XSLTInputSource(xslFilename);
// Create some XObjects to use
org.apache.xalan.xpath.XBoolean myBoolean =
processor.createXBoolean(true);
org.apache.xalan.xpath.XNull myNull = processor.createXNull();
org.apache.xalan.xpath.XNumber myNumber =
processor.createXNumber(1);
org.apache.xalan.xpath.XObject myObject =
processor.createXObject("a");
org.apache.xalan.xpath.XString myString =
processor.createXString("a");
// Test setting the value and checking it in a select expr
processor.setStylesheetParam("t1", myNull);
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,false,false,</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr with XNull");
processor.setStylesheetParam("t1", myBoolean);
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>true,false,true,true,true</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr with XBoolean");
processor.setStylesheetParam("t1", myString); // XString = "a"
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,true,false,a</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr with XString");
processor.setStylesheetParam("t1", myObject); // XObject = (string)"a"
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,true,false,a</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr with xObject(string)");
processor.setStylesheetParam("t1", myNumber);
processor.process(xmlSource, xslStylesheet,
new XSLTResultTarget(outNames.nextName()));
processor.reset();
checkFileContains(outNames.currentName(),
"<outt>false,false,false,true,1</outt>",
"out(" + outNames.currentCounter()
+ ") Select expr with XNumber");
}
catch (Exception e)
{
reporter.checkErr("Testcase threw: " + e.toString());
}
reporter.testCaseClose();
return true;
}
/**
* Checks and reports if a file contains a certain string (within one line).
* <P>We should really validate the entire output file, but this will do for now.</P>
* @todo update to use new CheckServices!
*
* NEEDSDOC @param fName
* NEEDSDOC @param checkStr
* NEEDSDOC @param comment
*
* NEEDSDOC ($objectName$) @return
*/
protected boolean checkFileContains(String fName, String checkStr,
String comment)
{
boolean passFail = false;
File f = new File(fName);
if (!f.exists())
{
reporter.checkFail("checkFileContains(" + fName
+ ") does not exist: " + comment);
return false;
}
try
{
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
for (;;)
{
String inbuf = br.readLine();
if (inbuf == null)
break;
if (inbuf.indexOf(checkStr) > 0)
{
passFail = true;
reporter.logTraceMsg(
"checkFileContains passes with line: " + inbuf);
break;
}
}
}
catch (IOException ioe)
{
reporter.checkFail("checkFileContains(" + fName + ") threw: "
+ ioe.toString() + " for: " + comment);
return false;
}
reporter.check(passFail, true, comment);
return passFail;
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by ParamTest:\n"
+ "(Note: assumes inputDir=.\\prod\\conf)\n" + super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
ParamTest app = new ParamTest();
app.doMain(args);
}
} // end of class ParamTest
1.1 xml-xalan/test/java/src/org/apache/qetest/xalanj1/package.html
Index: package.html
===================================================================
<html>
<title>XSL-TEST TRAX testing package.</title>
<body>
<p>This package is for Xalan-J 1.x API tests.<p>
<dl>
<dt><b>Author: </b></dt><dd><a href="mailto:shane_curcuru@lotus.com">Shane_Curcuru@lotus.com</a></dd>
<dt><b>Program(s) Under Test: </b></dt>
<dd><a href="http://xml.apache.org/xalan" target="_top">Xalan-J 1.x XSLT Processor</a></dd>
</dl>
<p>To be filled in!.<p>
<ul>Current tests are primarily focused on covering the API's and include:
<li>ParamTest - basic setParameter functionality.</li>
<li>More tests are needed, although I may be spending more of
my time writing TRAX or Xalan-J 2.x tests.</li>
</ul>
</body>
</html>
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/CConformanceTest.java
Index: CConformanceTest.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/>.
*/
/*
*
* CConformanceTest.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import org.apache.qetest.xslwrapper.ProcessorWrapper; // Merely for the ERROR constant
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Vector;
//-------------------------------------------------------------------------
/**
* New! CConformanceTest for Xalan-C's TestXSLT.exe program.
* <p>Iterates over all conformance tests using common functionality,
* then shells out a process to TestXSLT.exe for each test.
* Automatically validates output files against golds, but may not
* validate error or exception conditions yet.</p>
* @author shane_curcuru@lotus.com
*/
public class CConformanceTest extends XSLDirectoryIterator
{
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by CConformanceTest:\n"
+ " -progName <name.exe>\n"
+ " -progPath <d:\\path\\to\\prog>\n" + super.usage());
}
/** Array of 'command line' args for Process.main(args) calls. */
String[] pargs = null;
/**
* Parameter: Actual name of external program to call.
* <p>Default: TestXSLT</p>
*/
String progName = "TestXSLT";
/**
* Parameter: Actual name of external program to call.
* <p>Default: TestXSLT</p>
*/
public static final String OPT_PROGNAME = "progName";
/**
* Path to external program to call.
* <p>Default: blank string</p>
*/
String progPath = "";
/**
* Path to external program to call.
* <p>Default: blank string</p>
*/
public static final String OPT_PROGPATH = "progPath";
/**
* Parameter: -precompile If we should precompile (and
* serialize) stylesheets separately first.
* <p>Default: false. Note: Likely not supported in early C++ releases.</p>
*/
boolean precompile = false;
/**
* Default constructor - initialize testName, Comment.
*/
public CConformanceTest()
{
testName = "CConformanceTest";
testComment =
"Iterates over all conf test dirs and validates outputs using Xalan-C";
}
/**
* Initialize this test - process our input args and construct
* array of command line args for processor.
* @todo make this table-driven for the argument names
* @todo update to include all supported args
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Validate/setup progName, progPath
progName = testProps.getProperty(OPT_PROGNAME, progName);
progPath = testProps.getProperty(OPT_PROGPATH, progPath);
reporter.logTraceMsg("progPath\\progName= " + progPath
+ File.separator + progName);
// Attempt to check if it exists (but only in certain cases)
if ((progPath != null) && (progPath.length() > 0))
{
File progF = new File(progPath + File.separator + progName);
if (!progF.exists())
{
reporter.logErrorMsg("Program may not exist! " + progPath
+ File.separator + progName);
}
}
else
{
// No-op: can't easily validate programs (presumably) found on the PATH
}
Vector vec = new Vector();
// Set up pargs with global args from our inputs; used in every process
// Standard args that XLTest supports:
if ((liaison == null) || ("".equals(liaison)))
{
// no-op, don't use null or blank liaison
}
else
{
// setup args for liaison - note must be fully qualified classname
vec.addElement("-PARSER");
vec.addElement(liaison);
}
// Only pass the indent if it was explicitly set
if (indentLevel > NO_INDENT)
{
vec.addElement("-INDENT");
vec.addElement(Integer.toString(indentLevel));
}
// precompile is supported in processSingleFile
// Unsupported: flavor - not very useful!
// Unsupported: diagName
// Unsupported: noReuse
// Gadzillions of args that Process supports:
setSingleArg("E", testProps, vec); //" [-E (Do not expand entity refs)]");
setSingleArg("V", testProps, vec); //" [-V (Version info)]");
setSingleArg("QC", testProps, vec); //" [-QC (Quiet Pattern Conflicts Warnings)]");
setSingleArg("Q", testProps, vec); //" [-Q (Quiet Mode)]");
setSingleArg("LF", testProps, vec); //" [-LF (Use linefeeds only on output {default is CR/LF})]");
setSingleArg("CR", testProps, vec); //" [-CR (Use carriage returns only on output {default is CR/LF})]");
setSingleArg("TT", testProps, vec); //" [-TT (Trace the templates as they are being called.)]");
setSingleArg("TG", testProps, vec); //" [-TG (Trace each generation event.)]");
setSingleArg("TS", testProps, vec); //" [-TS (Trace each selection event.)]");
setSingleArg("TTC", testProps, vec); //" [-TTC (Trace the template children as they are being processed.)]");
setSingleArg("VALIDATE", testProps, vec); //" [-VALIDATE (Set whether validation occurs. Validation is off by default.)]");
setSingleArg("XML", testProps, vec); //" [-XML (Use XML formatter and add XML header.)]");
setSingleArg("TEXT", testProps, vec); //" [-TEXT (Use simple Text formatter.)]");
setSingleArg("HTML", testProps, vec); //" [-HTML (Use HTML formatter.)]");
setSingleArg("SX", testProps, vec); //" [-SX (Xerces serializers)]");
// FIXME: Args not yet tested
//" [-ESCAPE (Which characters to escape {default is <>&\"\'\\r\\n}]");
//" [-TCLASS (TraceListener class for trace extensions.)]");
//" [-EDUMP {optional filename} (Do stackdump on error.)]");
//" [-PARAM name expression (Set a stylesheet parameter)]");
// Copy the vector into array
pargs = new String[vec.size()];
vec.copyInto(pargs);
reporter.logTraceMsg("Default arguments vector: " + vec.toString());
return true;
}
/**
* Worker method to add a single "-"arg if found in properties block.
*
* NEEDSDOC @param name
* NEEDSDOC @param p
* NEEDSDOC @param v
*/
protected void setSingleArg(String name, Properties p, Vector v)
{
final String tmp = (String) p.get(name);
if (tmp != null) // Note: adds it even if it's blank!
{
v.addElement("-" + name);
}
}
/**
* Subclassed callback to provide info about the processor you're testing.
*
* NEEDSDOC ($objectName$) @return
*/
public String getProcessorDescription()
{
return "ProcessorVersion;command line TestXSLT.exe:Xalan only";
}
/**
* Run through the directory given to us and run tests found in subdirs.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean runTestCases(Properties p)
{
// Use all the default directory processing methods
// from our parent XLDirectoryIterator
processTestDir();
return true;
}
/**
* Run one xsl/xml file pair through the processor.
* <p>We simply call Process.main() with a constructed series
* of args[] using Runtime.exec().</p>
* <p>Note that timings are in no way comparable to the normal
* ConformanceTest since this is C++, not Java, and since we have
* the overhead of shelling out the process and processing
* the command line.</p>
*
* NEEDSDOC @param XMLName
* NEEDSDOC @param XSLName
* NEEDSDOC @param OutName
*
* NEEDSDOC ($objectName$) @return
*/
public int processSingleFile(String XMLName, String XSLName,
String OutName)
{
long fileTime = ProcessorWrapper.ERROR;
try
{
if (precompile)
{
reporter.checkFail(
"Sorry, precompile option not supported yet!");
return UNEXPECTED_EXCEPTION;
} // of if (precompile)
String args[] = new String[pargs.length + 7]; // progName -in XML -xsl XSL -out OUT
if ((progPath != null) && (progPath.length() > 0))
{
args[0] = progPath + File.separator + progName;
}
else
{
// Pesume the program is on the PATH already...
args[0] = progName;
}
args[1] = "-in";
args[2] = translateInputName(XMLName);
args[3] = "-xsl";
args[4] = translateInputName(XSLName);
args[5] = "-out";
args[6] = translateOutputName(OutName);
System.arraycopy(pargs, 0, args, 7, pargs.length);
if (debug)
{
for (int x = 0; x < args.length; x++)
{
reporter.logTraceMsg("arg[" + x + "]=" + args[x]);
}
}
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
int returnVal = 0;
startTime = System.currentTimeMillis();
// Use our worker method to execute the process
returnVal = execProcess(args, null);
endTime = System.currentTimeMillis();
fileTime = endTime - startTime;
// if the execution of the process was basically OK,
// then add this file to overall timing info
if (returnVal != ProcessorWrapper.ERROR)
{
dirTime += fileTime;
dirFilesProcessed++;
reporter.logTraceMsg("processSingleFile(" + XSLName
+ ") no exceptions; time " + fileTime);
reporter.logInfoMsg("processSingleFile(" + XSLName
+ ") returnValue = " + returnVal);
}
else
{
// Do not increment performance counters if there's an error
// Note: can this code ever really be executed?
reporter.logWarningMsg("processSingleFile(" + XSLName
+ ") returned ERROR code!");
}
}
// Catch general Exceptions, check if they're expected, and restart
catch (Exception e)
{
reporter.logStatusMsg("processSingleFile(" + XSLName
+ ") threw: " + e.toString());
int retVal = checkExpectedException(e, XSLName, OutName);
return retVal;
}
// Catch any Throwable, check if they're expected, and restart
catch (Throwable t)
{
reporter.logStatusMsg("processSingleFile(" + XSLName
+ ") threw: " + t.toString());
int retVal = checkExpectedException(t, XSLName, OutName);
return retVal;
}
return PROCESS_OK;
}
/**
* Worker method to translate filenames into appropriate format for C program.
* <p>Always returns a string - will be blank if the file does not exist
* or if we can't figure out the appropriate name to use</p>
* @param name of file
* @return appropriate translation into format that the .exe expects for -in, -xsl
*/
public String translateInputName(String name)
{
StringBuffer ret = new StringBuffer("file:///");
File f = new File(name);
try
{
// This gives the best path, I think, but may throw exceptions
ret.append(f.getCanonicalPath());
}
catch (Exception e)
{
// This should work in most cases
ret.append(f.getAbsolutePath());
}
return ret.toString();
}
/**
* Worker method to translate filenames into appropriate format for C program.
* <p>Always returns a string - will be blank if the file does not exist
* or if we can't figure out the appropriate name to use</p>
* @param name of file
* @return appropriate translation into format that the .exe expects for -out
*/
public String translateOutputName(String name)
{
// Hopefully, we don't need translation on the output name
return name;
}
/**
* Simple child thread for reading an InputStream.
* Used to capture the System.err and System.out streams
* from the executed process - without hanging or blocking.
*/
public class ThreadedStreamReader extends Thread
{ // Begin of inner class
/** NEEDSDOC Field is */
BufferedReader is = null;
/** NEEDSDOC Field sb */
StringBuffer sb = null;
/**
* NEEDSDOC Method setInputStream
*
*
* NEEDSDOC @param set
*/
public void setInputStream(BufferedReader set)
{
is = set;
}
/**
* NEEDSDOC Method run
*
*/
public void run()
{
sb = new StringBuffer();
// Note that reporters may not be threadsafe, so we should avoid there use herein
if (is == null)
{
sb.append(
"ERROR! ThreadedStreamReader.run() with setInputStream(null)");
return;
}
sb.append("<tsrbuf>");
String i = null;
try
{
i = is.readLine();
}
catch (IOException ioe1)
{ // Presumably the stream is bad, so just bag out
i = null;
}
while (i != null)
{
sb.append(i);
try
{
i = is.readLine();
}
catch (IOException ioe2)
{ // Presumably the stream is bad, so just bag out
i = null;
}
}
sb.append("</tsrbuf>");
}
/**
* NEEDSDOC Method getBuffer
*
*
* NEEDSDOC (getBuffer) @return
*/
public StringBuffer getBuffer()
{
return sb;
}
}
; // End of inner class
/**
* Worker method to shell out an external process.
* <p>Does a simple capturing of the out and err streams from
* the process. Inherits the same environment that the current
* JVM is in.</p>
* @param cmdLine actual command line to run, including program name
* NEEDSDOC @param environment
* @return return value from program
* @exception Exception may be thrown by Runtime.exec
*/
public int execProcess(String[] cmdLine, String[] environment)
throws Exception
{
// @todo check the logic here: will '-1' be a likely
// return value from the process anyways?
// this is needed in our caller to see if they should
// use this process as part of timing data
int retVal = (new Long(ProcessorWrapper.ERROR)).intValue();
if ((cmdLine == null) || (cmdLine.length < 1))
{
reporter.logErrorMsg(
"execProcess called with null/blank arguments!");
return retVal;
}
int bufSize = 2048;
ThreadedStreamReader outReader = new ThreadedStreamReader();
ThreadedStreamReader errReader = new ThreadedStreamReader();
Runtime r = Runtime.getRuntime();
java.lang.Process proc = null; // Fully declare to not conflict with org.apache.xalan.xslt.Process
// Actually begin executing the program
reporter.logTraceMsg("execProcess starting " + cmdLine[0]);
proc = r.exec(cmdLine, environment);
// Immediately begin capturing any output therefrom
outReader.setInputStream(
new BufferedReader(
new InputStreamReader(proc.getInputStream()), bufSize));
errReader.setInputStream(
new BufferedReader(
new InputStreamReader(proc.getErrorStream()), bufSize));
// Start two thread off on reading the System.out and System.err from proc
outReader.start();
errReader.start();
try
{
// Wait for the process to exit normally
retVal = proc.waitFor();
}
catch (InterruptedException ie1)
{
reporter.logWarningMsg("execProcess proc.waitFor() threw: "
+ ie1.toString());
}
// Now that we're done, presumably the Readers are also done
String sysOut = "No System.out captured";
String sysErr = "No System.err captured";
try
{
outReader.join();
sysOut = outReader.getBuffer().toString();
}
catch (InterruptedException ie2)
{
reporter.logWarningMsg("Joining outReader threw: "
+ ie2.toString());
}
try
{
errReader.join();
sysErr = errReader.getBuffer().toString();
}
catch (InterruptedException ie3)
{
reporter.logWarningMsg("Joining errReader threw: "
+ ie3.toString());
}
reporter.logArbitrary(reporter.INFOMSG,
"proc.System.out was: " + sysOut);
reporter.logArbitrary(reporter.INFOMSG,
"proc.System.err was: " + sysErr);
reporter.logTraceMsg("execProcess exitVal=" + retVal);
return retVal;
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
CConformanceTest app = new CConformanceTest();
app.doMain(args);
}
} // end of class CConformanceTest
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/ConformanceDirRules.java
Index: ConformanceDirRules.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/>.
*/
package org.apache.qetest.xsl;
import java.io.FilenameFilter;
import java.io.File;
import java.util.Hashtable;
/**
* Returns directories that are either on an inclusion list, or
* just ones that don't begin with [x|X], or are 'CVS'.
* @author shane_curcuru@lotus.com
* @version $Id: ConformanceDirRules.java,v 1.1 2000/11/01 23:26:56 curcuru Exp $
*/
public class ConformanceDirRules implements FilenameFilter
{
/** Initialize for defaults (not using inclusion list) no-op. */
public ConformanceDirRules(){}
/**
* Initialize with a case-sensitive Hash of directory names to include.
*
* NEEDSDOC @param iDirs
*/
public ConformanceDirRules(Hashtable iDirs)
{
setIncludeDirs(iDirs);
}
/**
* Initialize with a case-insensitive String directory name to include.
*
* NEEDSDOC @param incDir
*/
public ConformanceDirRules(String incDir)
{
setIncludeDirs(incDir);
}
/**
* Hash of directory names to include.
* <p>Keys are dir names, values in hash are ignored. Note that
* directory names are case-sensitive. If list is not set somehow,
* then we return all dirs that don't begin with [x|X].</p>
*/
protected Hashtable includeDirs = null;
/** Exclude CVS repository dirs always. */
public static final String CVS = "CVS";
/**
* Accessor methods for case-sensitive Hash of directory names to include.
*
* NEEDSDOC @param iDirs
*/
public void setIncludeDirs(Hashtable iDirs)
{
if (iDirs != null)
includeDirs = (Hashtable) iDirs.clone();
else
includeDirs = null;
}
/**
* Accessor methods for case-sensitive Hash of directory names to include.
*
* NEEDSDOC ($objectName$) @return
*/
public Hashtable getIncludeDirs()
{
if (includeDirs != null)
{
Hashtable tempHash = (Hashtable) includeDirs.clone();
return (tempHash);
}
else
{
return null;
}
}
/**
* Accessor method to set a case-insensitive String directory name to include.
*
* NEEDSDOC @param incDir
*/
public void setIncludeDirs(String incDir)
{
setIncludeDirs(incDir, false);
}
/**
* Accessor method to set an optionally case-sensitive String directory name to include.
* <p><b>Note:</b> simply uses .toUpperCase() and .toLowerCase() on the input string;
* does not do full case-checking on the entire string!</p>
*
* NEEDSDOC @param incDir
* NEEDSDOC @param caseSensitive
*/
public void setIncludeDirs(String incDir, boolean caseSensitive)
{
if ((incDir != null) && (incDir != ""))
{
includeDirs = null;
includeDirs = new Hashtable();
includeDirs.put(incDir, "");
if (!caseSensitive)
{
includeDirs.put(incDir.toUpperCase(), "");
includeDirs.put(incDir.toLowerCase(), "");
}
}
else
{
includeDirs = null;
}
}
/**
* Tests if a specified file should be included in a file list.
* Returns only directories that are on our inclusion list.
* Currently may be case-sensitive or insensitive, depending on
* how/if our inclusion list was set.
* @param dir the directory in which the file was found.
* @param name the name of the file.
* @return <code>true</code> if the name should be included in the file list; <code>false</code> otherwise.
* @since JDK1.0
*/
public boolean accept(File dir, String name)
{
// Shortcut to only look at directories
File file = new File(dir, name);
if (!file.isDirectory())
return (false);
// If we have an inclusion list, just look at that
if (includeDirs != null)
{
if (includeDirs.containsKey(name))
return (true);
else
return (false);
}
// Otherwise, exclude any other names that begin with [x|X]
char firstChar = name.charAt(0);
if ((firstChar == 'x') || (firstChar == 'X'))
return (false);
else if (CVS.equals(name)) // ALSO: exclude "CVS" dirs from our source control
return (false);
else
return (true);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/ConformanceErrFileRules.java
Index: ConformanceErrFileRules.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/>.
*/
package org.apache.qetest.xsl;
import java.io.FilenameFilter;
import java.io.File;
/**
* Simple file filter; returns *.xsl non-dir files that match a parent + directory name.
* @author shane_curcuru@lotus.com
* @version $Id: ConformanceErrFileRules.java,v 1.1 2000/11/01 23:26:56 curcuru Exp $
*/
public class ConformanceErrFileRules implements FilenameFilter
{
/**
* Initialize with a case-insensitive name of parent directory.
*
* NEEDSDOC @param p
*/
public ConformanceErrFileRules(String p)
{
if (p != null)
parentName = p;
}
/** Case-insensitive name of parent directory; used in {@link accept(java.io.File, java.lang.String)}. */
protected String parentName = "";
/**
* Tests if a specified file should be included in a file list.
* <p>Returns true only for *.xsl files whose names start with
* the name of the parent + name of the directory, case-insensitive (uses .toLowerCase()).</p>
* @param dir the directory in which the file was found.
* @param name the name of the file.
* @return <code>true</code> if the name should be included in the file list; <code>false</code> otherwise.
* @since JDK1.0
*/
public boolean accept(File dir, String name)
{
if (name == null || dir == null)
return (false);
File file = new File(dir, name);
return (!file.isDirectory()) && name.toLowerCase().endsWith("xsl")
&& name.toLowerCase().startsWith(
parentName.toLowerCase() + dir.getName().toLowerCase());
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/ConformanceFileRules.java
Index: ConformanceFileRules.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/>.
*/
package org.apache.qetest.xsl;
import java.io.FilenameFilter;
import java.io.File;
import java.util.Hashtable;
import java.util.StringTokenizer;
/**
* Simple file filter; returns *.xsl non-dir files that start with the directory name.
* Has crude support for an excludes list of filename bases.
* @author shane_curcuru@lotus.com
* @version $Id: ConformanceFileRules.java,v 1.1 2000/11/01 23:26:56 curcuru Exp $
*/
public class ConformanceFileRules implements FilenameFilter
{
/** Initialize for defaults (not using inclusion list) no-op. */
public ConformanceFileRules(){}
/**
* Initialize with a case-sensitive Hash of file names to exclude.
*
* NEEDSDOC @param excludesHash
*/
public ConformanceFileRules(Hashtable excludesHash)
{
setExcludes(excludesHash);
}
/**
* Initialize with a case-insensitive semicolon-delimited String of file names to exclude.
*
* NEEDSDOC @param excludesStr
*/
public ConformanceFileRules(String excludesStr)
{
setExcludes(excludesStr);
}
/**
* Hash of file name portions to exclude.
* <p>Keys are base file names, values in hash are ignored. Note that
* file names may be case-sensitive.</p>
* <p>Note that we will exclude any filename in our excludes.</p>
*/
protected Hashtable excludeFiles = null;
/**
* Accessor methods to set a case-sensitive Hash of file names to exclude.
*
* NEEDSDOC @param exFiles
*/
public void setExcludes(Hashtable exFiles)
{
if (exFiles != null)
excludeFiles = (Hashtable) exFiles.clone();
else
excludeFiles = null;
}
/**
* Accessor methods to set a case-sensitive Hash of file names to exclude.
*
* NEEDSDOC ($objectName$) @return
*/
public Hashtable getExcludes()
{
if (excludeFiles != null)
{
Hashtable tempHash = (Hashtable) excludeFiles.clone();
return tempHash;
}
else
{
return null;
}
}
/**
* Accessor method to set a list of case-insensitive String
* directory name(s) to exclude.
* Names should be separated by {@link #SEPARATOR semicolon}.
*
* NEEDSDOC @param exFiles
*/
public void setExcludes(String exFiles)
{
setExcludes(exFiles, false);
}
/** Semicolon separator for {@link #setExcludes(java.lang.String)}. */
public static final String SEPARATOR = ";";
/**
* Accessor method to set an optionally case-sensitive String file name(s) to exclude.
* <p><b>Note:</b> simply uses .toUpperCase() and .toLowerCase() on the input string(s);
* does not do full case-checking on the entire string!</p>
*
* NEEDSDOC @param exFiles
* NEEDSDOC @param caseSensitive
*/
public void setExcludes(String exFiles, boolean caseSensitive)
{
StringTokenizer st = new StringTokenizer(exFiles, SEPARATOR);
excludeFiles = null;
excludeFiles = new Hashtable();
for (int i = 0; st.hasMoreTokens(); i++)
{
String fName = st.nextToken();
excludeFiles.put(fName, "");
if (!caseSensitive)
{
excludeFiles.put(fName.toUpperCase(), "");
excludeFiles.put(fName.toLowerCase(), "");
}
}
}
/**
* Tests if a specified file should be included in a file list.
* <p>Returns true only for *.xsl files whose names start with
* the name of the directory, case-insensitive (uses .toLowerCase()).
* <b>Except:</b> if any filenames contain an item in excludeFiles.</p>
* @param dir the directory in which the file was found.
* @param name the name of the file.
* @return <code>true</code> if the name should be included in the file list; <code>false</code> otherwise.
* @since JDK1.0
*/
public boolean accept(File dir, String name)
{
// Shortcuts for bogus filenames and dirs
if (name == null || dir == null)
return false;
// Exclude any files that match an exclude rule
if ((excludeFiles != null) && (excludeFiles.containsKey(name)))
return false;
File file = new File(dir, name);
return (!file.isDirectory()) && name.toLowerCase().endsWith("xsl")
&& name.toLowerCase().startsWith(dir.getName().toLowerCase());
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/ConformanceTest.java
Index: ConformanceTest.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/>.
*/
/*
*
* ConformanceTest.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Properties;
//-------------------------------------------------------------------------
/**
* New, Improved! ConformanceTest.
* <p>Note that other than setting up our name and comment, and determining
* the processor's description, we simply use all the default implementations
* of methods from XSLDirectoryIterator.</p>
* @author shane_curcuru@lotus.com
*/
public class ConformanceTest extends XSLDirectoryIterator
{
/**
* Default constructor - initialize testName, Comment.
*/
public ConformanceTest()
{
testName = "ConformanceTest";
testComment =
"Iterates over all conf test dirs and validates outputs";
}
/**
* Initialize this test - setup description and createNewProcessor.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// Create a processor with our appropriate flavor, etc.
if (!createNewProcessor())
{
reporter.logErrorMsg(
"Could not createNewProcessor before testing; it won't work!");
return false;
}
return true;
}
/**
* Run through the directory given to us and run tests found
* in subdirs; or run through our fileList.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean runTestCases(Properties p)
{
// The ConformanceTest simply uses all the default processing methods
// from our parent XSLDirectoryIterator
// Note that we skip executeTests and the number of
// test cases we have, since we just iterate over
// fileLists or directories
processTestDir();
return true;
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
ConformanceTest app = new ConformanceTest();
app.doMain(args);
}
} // end of class ConformanceTest
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/LoggingEntityResolver.java
Index: LoggingEntityResolver.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/>.
*/
/*
*
* LoggingEntityResolver.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import java.io.IOException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
//-------------------------------------------------------------------------
/**
* Implementation of EntityResolver that logs all calls.
* Currently just provides default service; returns null.
* @author shane_curcuru@lotus.com
* @version $Id: LoggingEntityResolver.java,v 1.1 2000/11/01 23:26:56 curcuru Exp $
*/
public class LoggingEntityResolver implements EntityResolver
{
/** No-op ctor since it's often useful to have one. */
public LoggingEntityResolver(){}
/**
* Ctor that calls setReporter automatically.
*
* NEEDSDOC @param r
*/
public LoggingEntityResolver(Reporter r)
{
setReporter(r);
}
/** Our Reporter, who we tell all our secrets to. */
private Reporter reporter;
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC @param r
*/
public void setReporter(Reporter r)
{
if (r != null)
reporter = r;
}
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC ($objectName$) @return
*/
public Reporter getReporter()
{
return (reporter);
}
/** Prefixed to all reporter msg output. */
private String prefix = "ER:";
/** Counters for how many entities we've 'resolved'. */
private int entityCtr = 0;
/**
* Accesor methods for entity counter.
*
* NEEDSDOC ($objectName$) @return
*/
public int getEntityCtr()
{
return entityCtr;
}
/**
* Cheap-o string representation of our state.
*
* NEEDSDOC ($objectName$) @return
*/
public String getCounterString()
{
return (prefix + "Entities: " + getEntityCtr());
}
/** Cheap-o string representation of last entity we resolved. */
private String lastEntity = null;
/**
* NEEDSDOC Method setLastEntity
*
*
* NEEDSDOC @param s
*/
protected void setLastEntity(String s)
{
lastEntity = s;
}
/**
* Accessor for string representation of last entity we resolved.
*
* NEEDSDOC ($objectName$) @return
*/
public String getLastEntity()
{
return lastEntity;
}
/** What loggingLevel to use for reporter.logMsg(). */
private int level = Reporter.DEFAULT_LOGGINGLEVEL;
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC @param l
*/
public void setLoggingLevel(int l)
{
level = l;
}
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC ($objectName$) @return
*/
public int getLoggingLevel()
{
return level;
}
/**
* Implement this method: just returns null for now.
* Also saves the last entity for later retrieval, and counts
* how many entities we've 'resolved' overall.
* @todo have a settable property to actually return as the InputSource
*
* NEEDSDOC @param publicId
* NEEDSDOC @param systemId
*
* NEEDSDOC ($objectName$) @return
* @exception SAXException never thrown
* @exception IOException never thrown
*/
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException
{
entityCtr++;
setLastEntity(publicId + ";" + systemId);
if (reporter != null)
{
reporter.logMsg(level,
prefix + getLastEntity() + " "
+ getCounterString());
}
return null;
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/LoggingSAXErrorHandler.java
Index: LoggingSAXErrorHandler.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/>.
*/
/*
*
* LoggingSAXErrorHandler.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
//-------------------------------------------------------------------------
/**
* Cheap-o ErrorHandler for use by API tests.
* <p>Implements org.xml.sax.ErrorHandler and dumps everything to a Reporter.</p>
* @author shane_curcuru@lotus.com
* @version $Id: LoggingSAXErrorHandler.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class LoggingSAXErrorHandler implements ErrorHandler
{
/** No-op ctor seems useful. */
public LoggingSAXErrorHandler(){}
/**
* Ctor that calls setReporter automatically.
*
* NEEDSDOC @param r
*/
public LoggingSAXErrorHandler(Reporter r)
{
setReporter(r);
}
/** Our Reporter, who we tell all our secrets to. */
private Reporter reporter;
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC @param r
*/
public void setReporter(Reporter r)
{
if (r != null)
reporter = r;
}
/**
* Accesor methods for our Reporter.
*
* NEEDSDOC ($objectName$) @return
*/
public Reporter getReporter()
{
return (reporter);
}
/** Prefixed to all reporter msg output. */
private String prefix = "SEH:";
/** Constants determining when we should throw exceptions. */
public static final int THROW_NEVER = 0;
/** NEEDSDOC Field THROW_ON_WARNING */
public static final int THROW_ON_WARNING = 1;
/** NEEDSDOC Field THROW_ON_ERROR */
public static final int THROW_ON_ERROR = 2;
/** NEEDSDOC Field THROW_ON_FATAL */
public static final int THROW_ON_FATAL = 4;
/** NEEDSDOC Field THROW_ALWAYS */
public static final int THROW_ALWAYS = THROW_ON_WARNING & THROW_ON_ERROR
& THROW_ON_FATAL;
/** If we should throw an exception for each message type. */
private int throwWhen = THROW_ON_FATAL;
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC @param t
*/
public void setThrowWhen(int t)
{
throwWhen = t;
}
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC ($objectName$) @return
*/
public int getThrowWhen()
{
return throwWhen;
}
/** Counters for how many problems or messages we've processed. */
private int warningCtr = 0;
/** NEEDSDOC Field errorCtr */
private int errorCtr = 0;
/** NEEDSDOC Field fatalCtr */
private int fatalCtr = 0;
/**
* Accesor methods for counters.
*
* NEEDSDOC ($objectName$) @return
*/
public int getWarningCtr()
{
return warningCtr;
}
/**
* Accesor methods for counters.
*
* NEEDSDOC ($objectName$) @return
*/
public int getErrorCtr()
{
return errorCtr;
}
/**
* Accesor methods for counters.
*
* NEEDSDOC ($objectName$) @return
*/
public int getFatalCtr()
{
return fatalCtr;
}
/**
* Cheap-o string representation of our state.
*
* NEEDSDOC ($objectName$) @return
*/
public String getCounterString()
{
return (prefix + " Warnings: " + getWarningCtr() + ", Errors: "
+ getErrorCtr() + ", FatalErrors: " + getFatalCtr());
}
/** Cheap-o string representation of last warn/error/fatal we got. */
private String lastError = null;
/**
* NEEDSDOC Method setLastError
*
*
* NEEDSDOC @param s
*/
protected void setLastError(String s)
{
lastError = s;
}
/**
* Accessor for string representation of last warn/error/fatal we got.
*
* NEEDSDOC ($objectName$) @return
*/
public String getLastError()
{
return lastError;
}
/** What loggingLevel to use for reporter.logMsg(). */
private int level = Reporter.DEFAULT_LOGGINGLEVEL;
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC @param l
*/
public void setLoggingLevel(int l)
{
level = l;
}
/**
* Accesor methods; don't think it needs to be synchronized.
*
* NEEDSDOC ($objectName$) @return
*/
public int getLoggingLevel()
{
return level;
}
/**
* Grab basic info out of a SAXParseException.
*
* NEEDSDOC @param exception
*
* NEEDSDOC ($objectName$) @return
*/
public String getParseExceptionInfo(SAXParseException exception)
{
if (exception == null)
return null;
String retVal = new String("");
String tmp;
tmp = exception.getPublicId();
if (tmp != null)
retVal += " publicID:" + tmp;
tmp = exception.getSystemId();
if (tmp != null)
retVal += " systemId:" + tmp;
try
{
tmp = Integer.toString(exception.getLineNumber());
}
catch (NumberFormatException nfe)
{
tmp = null;
}
if (tmp != null)
retVal += " lineNumber:" + tmp;
try
{
tmp = Integer.toString(exception.getColumnNumber());
}
catch (NumberFormatException nfe)
{
tmp = null;
}
if (tmp != null)
retVal += " columnNumber:" + tmp;
tmp = exception.getMessage(); // Will grab inner message if needed
if (tmp != null)
retVal += " message:" + tmp;
return retVal;
}
/**
* Implementation of warning; calls logMsg with info contained in exception.
*
* NEEDSDOC @param exception
* @exception SAXException thrown only if asked to or if reporters are bad
*/
public void warning(SAXParseException exception) throws SAXException
{
// Increment counter, save the exception, and log what we got
warningCtr++;
String exInfo = getParseExceptionInfo(exception);
setLastError(exInfo);
if (reporter != null)
{
reporter.logMsg(level, prefix + " warning threw: " + exInfo);
reporter.logMsg(level, getCounterString());
}
if ((throwWhen & THROW_ON_WARNING) == THROW_ON_WARNING)
{
throw new SAXException(exception);
}
}
/**
* Implementation of error; calls logMsg with info contained in exception.
* Only ever throws an exception itself if asked to or if reporters are bad.
*
* NEEDSDOC @param exception
* @exception SAXException thrown only if asked to or if reporters are bad
*/
public void error(SAXParseException exception) throws SAXException
{
// Increment counter, save the exception, and log what we got
errorCtr++;
String exInfo = getParseExceptionInfo(exception);
setLastError(exInfo);
if (reporter != null)
{
reporter.logMsg(level, prefix + " error threw: " + exInfo);
reporter.logMsg(level, getCounterString());
}
if ((throwWhen & THROW_ON_ERROR) == THROW_ON_ERROR)
{
throw new SAXException(exception);
}
}
/**
* Implementation of error; calls logMsg with info contained in exception.
* Only ever throws an exception itself if asked to or if reporters are bad.
* Note that this may cause unusual behavior since we may not actually
* re-throw the exception, even though it was 'fatal'.
*
* NEEDSDOC @param exception
* @exception SAXException thrown only if asked to or if reporters are bad
*/
public void fatalError(SAXParseException exception) throws SAXException
{
// Increment counter, save the exception, and log what we got
fatalCtr++;
String exInfo = getParseExceptionInfo(exception);
setLastError(exInfo);
if (reporter != null)
{
reporter.logMsg(level, prefix + " fatal threw: " + exInfo);
reporter.logMsg(level, getCounterString());
}
if ((throwWhen & THROW_ON_FATAL) == THROW_ON_FATAL)
{
throw new SAXException(exception);
}
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/PerformanceTest.java
Index: PerformanceTest.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/>.
*/
/*
*
* PerformanceTest.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import org.apache.qetest.xslwrapper.*;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Properties;
//-------------------------------------------------------------------------
/**
* New, Improved! PerformanceTest - benchmark repetitive timings of various processors.
* <p>While the test harness does add a small amount of overhead to the benchmark
* process, this makes reporting and running the test much easier.</p>
* @author shane_curcuru@lotus.com
* @todo improve verification; make calling fileChecker conditional,
* perhaps only every 10 iterations or something
*/
public class PerformanceTest extends XSLDirectoryIterator
{
/**
* Parameter: Should we preload a single process before timing iterations?
* <p>Default: false. Format: -preload true|false</p>
*/
public static final String OPT_PRELOAD = "preload";
/** NEEDSDOC Field preload */
protected boolean preload = false;
/**
* Parameter: How many iterations should we make for each file?
* <p>Default: 3. Format: -iterations int</p>
*/
public static final String OPT_ITERATIONS = "iterations";
/** NEEDSDOC Field iterations */
protected int iterations = 3;
/** Markers for performance logging - Preload time. */
public static final String PERF_PRELOAD = "UPre";
/** Markers for performance logging - single iteration time. */
public static final String PERF_ITERATION = "UItr";
/** Markers for performance logging - average of iteration times. */
public static final String PERF_AVERAGE = "UAvg";
/** Markers for memory logging. */
public static final String PERF_MEMORY = "UMem";
/** Default ctor initializes test name, comment. */
public PerformanceTest()
{
testName = "PerformanceTest";
testComment =
"Iterates over all perf test dirs and writes timing info";
}
/**
* Initialize this test - setup description and createNewProcessor.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean doTestFileInit(Properties p)
{
// HACK Explicitly set diagnostics to null
// If we leave it set, then this will affect the processorWrapper
// and that may affect different processors differently
diagnostics = null;
// Read in our additional options from properties block (XLTest should have set this)
String tmp;
tmp = testProps.getProperty(OPT_PRELOAD, null);
if ((tmp != null) && tmp.equalsIgnoreCase("true"))
{
preload = true;
}
tmp = null;
tmp = testProps.getProperty(OPT_ITERATIONS, null);
try
{
iterations = Integer.parseInt(tmp);
}
catch (NumberFormatException numEx)
{
// no-op; leave as default
}
// Create a processor with our appropriate flavor, etc.
// This is really only done to let XLDirectoryIterator later on
// print out the flavor & version of the processor
// Note: This processor will get destroyed later on anyway:
// for the performance test, we re-create for each file
if (!createNewProcessor())
{
reporter.logErrorMsg(
"Could not createNewProcessor before testing; it may not work!");
}
return true;
}
/**
* Run through the directory given to us and run tests found in subdirs.
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean runTestCases(Properties p)
{
// The PerformanceTest simply uses all the default processing methods
// from our parent XLDirectoryIterator
logMemory(true); // dumps Runtime.freeMemory/totalMemory
processTestDir();
logMemory(true); // dumps Runtime.freeMemory/totalMemory
return true;
}
/**
* Run one xsl/xml file pair through the processor; looping and capturing timing info.
* @author Shane Curcuru
*
* NEEDSDOC @param XMLName
* NEEDSDOC @param XSLName
* NEEDSDOC @param OutName
* @return int status - pass, fail, expected exception or unexpected exception
* <p>processSingleFile should normally do all processing required to transform the XMLName,
* via the XSLName, into an OutName file on disk. It returns a status denoting
* what happend during the processing.</p>
* <p>For the PerformanceTest, we actually do a lot more:.</p>
* <UL>
* <LI>Create a new processorWrapper (and hence a new processor)</LI>
* <LI>If preload, run one process through first and report timing</LI>
* <LI>Iterate and perform a number of processes, timing for each one</LI>
* <LI>Cleanup what we can to not interfere with other tests later</LI>
* </UL>
* <p>Futurework: should we strip off just the filename and output just that
* in a specific format in the logPerfMsg calls to make it simpler to write reports?</p>
*/
public int processSingleFile(String XMLName, String XSLName,
String OutName)
{
long fileTime = ProcessorWrapper.ERROR;
try
{
// Force filerefs to be URI's if needed; Note that this may affect other processors besides xerces badly
if (useURI)
{
// Use this static convenience method; returns a URL; convert to String via toExternalForm()
// Note: we should consider caching the original strings first,
// in case we later on have a use for them instead of the URI'd format
XMLName = getURLFromString(XMLName, null).toExternalForm();
XSLName = getURLFromString(XSLName, null).toExternalForm();
// Note: Currently 28-Jun-00, the output of files is handled differently, so
// we do NOT want to convert those. Subject to change, however.
// OutName = getURLFromString(OutName, null).toExternalForm();
reporter.logTraceMsg("processSingleFile() useURI: "
+ XSLName);
}
// TODO replicate ProcessorBenchmark.benchmarkPreprocess()
// TODO cleanup outName - delete the file on disk
File outFile = new File(OutName);
try
{
boolean btmp = outFile.delete();
reporter.logTraceMsg("Deleting OutFile of::" + OutName
+ " status: " + btmp);
}
catch (SecurityException se)
{
reporter.logWarningMsg("Deleting OutFile of::" + OutName
+ " threw: " + se.toString());
// But continue anyways...
}
// Equivalent to ProcessorBenchmark.benchmark()
// Create a new wrapper & processor each time; cleanup stuff
processorW = null;
logMemory(true); // dumps Runtime.freeMemory/totalMemory
// Ask our utility routine for a new specific wrapper
// (Will automatically create a new wrapper and appropriate processor
if (!createNewProcessor())
{
reporter.logErrorMsg(
"ERROR: could not create processorWrapper, aborting.");
return UNEXPECTED_EXCEPTION;
}
// Prime the pump, so to speak, if desired
if (preload)
{
fileTime = processorW.processToFile(XMLName, XSLName,
OutName);
if (fileTime == ProcessorWrapper.ERROR)
{
reporter.logErrorMsg(
"ERROR: Preload process had a problem of::"
+ XSLName);
return UNEXPECTED_EXCEPTION;
}
reporter.logPerfMsg(PERF_PRELOAD, fileTime,
"Preload process of::" + XSLName);
}
logMemory(true); // dumps Runtime.freeMemory/totalMemory
long aggregate = 0L;
int j;
for (j = 1; j <= iterations; j++)
{
long retVal;
// Note: We re-write the same output file each time, so
// I suppose in theory that could affect future iterations
retVal = processorW.processToFile(XMLName, XSLName, OutName);
if (retVal == ProcessorWrapper.ERROR)
{
reporter.logErrorMsg(
"ERROR: processToFile problem on iteration(" + j
+ ") of::" + XSLName);
return UNEXPECTED_EXCEPTION;
}
aggregate += retVal;
reporter.logPerfMsg(PERF_ITERATION, retVal,
"processToFile(" + j + ") of::"
+ XSLName);
logMemory(true);
}
reporter.logPerfMsg(PERF_AVERAGE, (aggregate / iterations),
"Average of (" + iterations
+ ") iterations of::" + XSLName);
}
// Catch any throwable and log an error
catch (Throwable t)
{
reporter.logErrorMsg("processSingleFile of::" + XSLName
+ " threw: " + t.toString());
return UNEXPECTED_EXCEPTION;
}
return PROCESS_OK;
}
/**
* Cheap-o memory logger - just reports Runtime.totalMemory/freeMemory.
*
* NEEDSDOC @param total
*/
protected void logMemory(boolean total)
{
Runtime r = Runtime.getRuntime();
r.gc();
reporter.logPerfMsg(PERF_MEMORY, r.freeMemory(), "freeMemory");
if (total)
{
reporter.logPerfMsg(PERF_MEMORY, r.totalMemory(), "totalMemory");
}
}
/**
* Convenience method to print out usage information - update if needed.
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common [optional] options supported by PerformanceTest:\n"
+ " -" + OPT_PRELOAD
+ " run an extra process first, before looping\n" + " -"
+ OPT_ITERATIONS
+ " how many times to loop over each file\n"
+ super.usage());
}
/**
* Main method to run test from the command line - can be left alone.
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
PerformanceTest app = new PerformanceTest();
app.doMain(args);
}
} // end of class PerformanceTest
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/XHTComparator.java
Index: XHTComparator.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/>.
*/
/*
*
* XHTComparator.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.Reporter; // Only for PASS_RESULT, etc.
import java.io.PrintWriter;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.StringTokenizer;
// DOM imports from Xerces
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Text;
// Xerces imports
import org.apache.xerces.parsers.DOMParser;
import org.apache.xerces.dom.DOMImplementationImpl;
import org.apache.html.dom.HTMLBuilder;
// SAX2 imports from Xerces
import org.xml.sax.InputSource;
/**
* Uses an XML/HTML/Text diff comparator to check or diff two files.
* <p>Given two files, an actual test result and a known good or 'gold'
* test result, diff the two files to see if they are equal; if not, provide
* some very basic info on where they differ.</p>
* <p>Attempts to parse each file as an XML document using Xerces;
* if that fails, attempt to parse each as an HTML document using
* <i>NEED NEW HTML PARSER</i>; if that fails, pretend to parse each
* doc as a single text node.</p>
* @todo document whitespace difference handling better -sc
* @todo check how namespaces are handled and diff'd -sc
* @todo check how XML decls are handled (or not) -sc
* @todo check how files of different encodings are handled in each parse type -sc
* @todo Allow param to define the type of parse we do (i.e. if a
* testwriter knows their output file will be XML, we should only
* attempt to parse it as XML, not other types)
* @author Scott_Boag@lotus.com
* @author Shane_Curcuru@lotus.com
* @version $Id: XHTComparator.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class XHTComparator
{
/** NEEDSDOC Field MAX_VALUE_DISPLAY_LEN */
static final int MAX_VALUE_DISPLAY_LEN = 511; // arbitrary length, for convenience
/** NEEDSDOC Field maxDisplayLen */
private int maxDisplayLen = MAX_VALUE_DISPLAY_LEN;
/**
* NEEDSDOC Method setMaxDisplayLen
*
*
* NEEDSDOC @param i
*/
public void setMaxDisplayLen(int i)
{
if (i > 0)
maxDisplayLen = i;
}
/** Constants for reporting out reason for failed diffs. */
public static final String SEPARATOR = ";";
/** NEEDSDOC Field LBRACKET */
public static final String LBRACKET = "[";
/** NEEDSDOC Field RBRACKET */
public static final String RBRACKET = "]";
/** NEEDSDOC Field TEST */
public static final String TEST = "test";
/** NEEDSDOC Field GOLD */
public static final String GOLD = "gold";
/** NEEDSDOC Field PARSE_TYPE */
public static final String PARSE_TYPE = "-parse-type" + SEPARATOR; // postpended to TEST or GOLD
/** NEEDSDOC Field OTHER_ERROR */
public static final String OTHER_ERROR = "other-error" + SEPARATOR;
/** NEEDSDOC Field WARNING */
public static final String WARNING = "warning" + SEPARATOR;
/** NEEDSDOC Field MISMATCH_NODE */
public static final String MISMATCH_NODE = "mismatch-node" + SEPARATOR;
/** NEEDSDOC Field MISSING_TEST_NODE */
public static final String MISSING_TEST_NODE = "missing-node-" + TEST
+ SEPARATOR;
/** NEEDSDOC Field MISSING_GOLD_NODE */
public static final String MISSING_GOLD_NODE = "missing-node-" + GOLD
+ SEPARATOR;
/** NEEDSDOC Field MISMATCH_ATTRIBUTE */
public static final String MISMATCH_ATTRIBUTE = "mismatch-attribute"
+ SEPARATOR;
/** NEEDSDOC Field MISMATCH_VALUE */
public static final String MISMATCH_VALUE = "mismatch-value" + SEPARATOR;
/** NEEDSDOC Field MISSING_TEST_VALUE */
public static final String MISSING_TEST_VALUE = "missing-value-" + TEST
+ SEPARATOR;
/** NEEDSDOC Field MISSING_GOLD_VALUE */
public static final String MISSING_GOLD_VALUE = "missing-value-" + GOLD
+ SEPARATOR;
/** NEEDSDOC Field WHITESPACE_DIFF */
public static final String WHITESPACE_DIFF = "whitespace-diff;";
/**
* Compare two files by parsing into DOMs and comparing trees.
* @param goldFileName expected file
* @param testFileName actual file
* @param reporter PrintWriter to dump status info to
* @param array of warning flags (for whitespace diffs, I think?)
* NEEDSDOC @param warning
* @return true if they match, false otherwise
*/
public boolean compare(String goldFileName, String testFileName,
PrintWriter reporter, boolean[] warning)
{
// parse the gold doc
Document goldDoc = parse(goldFileName, reporter, GOLD);
// parse the test doc only if gold doc was parsed OK
Document testDoc = (null != goldDoc)
? parse(testFileName, reporter, TEST) : null;
if (null == goldDoc)
{
reporter.println(OTHER_ERROR + GOLD + SEPARATOR
+ "document null");
return false;
}
else if (null == testDoc)
{
reporter.println(OTHER_ERROR + TEST + SEPARATOR
+ "document null");
return false;
}
return diff(goldDoc, testDoc, reporter, warning);
}
// Reporter format:
// REASON_CONSTANT;gold val;test val;reason description
/**
* The contract is: when you enter here the gold and test nodes are the same type,
* both non-null, and both in the same basic position in the tree.
* @todo verify caller really performs for the contract -sc
*
* NEEDSDOC @param gold
* NEEDSDOC @param test
* NEEDSDOC @param reporter
* NEEDSDOC @param warning
*
* NEEDSDOC ($objectName$) @return
*/
boolean diff(Node gold, Node test, PrintWriter reporter,
boolean[] warning)
{
String name1 = gold.getNodeName();
String name2 = test.getNodeName();
// If both there but not equal, fail
if ((null != name1) && (null != name2) &&!name1.equals(name2))
{
reporter.print(MISMATCH_NODE + nodeTypeString(gold) + SEPARATOR
+ nodeTypeString(test) + SEPARATOR
+ "name does not equal test node");
return false;
}
else if ((null != name1) && (null == name2))
{
reporter.print(MISSING_TEST_NODE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + SEPARATOR
+ "name missing on test");
return false;
}
else if ((null == name1) && (null != name2))
{
reporter.print(MISSING_GOLD_NODE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + SEPARATOR
+ "name missing on gold");
return false;
}
String value1 = gold.getNodeValue();
String value2 = test.getNodeValue();
if ((null != value1) && (null != value2) &&!value1.equals(value2))
{
System.err.println("value1:");
System.err.println(value1);
System.err.println("value2:");
System.err.println(value2);
reporter.print(MISMATCH_VALUE + nodeTypeString(gold) + "-"
+ value1.length() + SEPARATOR
+ nodeTypeString(test) + "-" + value2.length()
+ SEPARATOR + "lengths do not match");
// Ignore old conditional printing; always print out values, even with newlines -sc
/**
* // semi-HACK: only report out stuff that's short enough
* // TODO This should be a settable property for the test harness! -sc
* if((value1.length() < maxDisplayLen)
* && (value2.length() < maxDisplayLen))
* {
* boolean doPrintValue = true;
* // TODO wouldn't it be more efficient to do indexOf's? -sc
* for(int i = 0; i < value1.length(); i++)
* {
* char c = value1.charAt(i);
* if((c == 0x0A) || (c == 0x0D) || (c == '\n'))
* {
* doPrintValue = false;
* break;
* }
* }
* if(doPrintValue)
* {
* for(int i = 0; i < value2.length(); i++)
* {
* char c = value2.charAt(i);
* if((c == 0x0A) || (c == 0x0D) || (c == '\n'))
* {
* doPrintValue = false;
* break;
* }
* }
* }
* if(doPrintValue)
* {
* / Ignore old conditional printing; always print out values, even with newlines -sc
*/
reporter.println();
reporter.print(MISMATCH_VALUE + value1 + SEPARATOR + value2
+ SEPARATOR + "values do not match");
return false;
}
else if ((null != value1) && (null == value2))
{
reporter.print(MISSING_TEST_VALUE + nodeTypeString(gold) + "-"
+ value1 + SEPARATOR + nodeTypeString(test)
+ SEPARATOR + "test no value");
return false;
}
else if ((null == value1) && (null != value2))
{
reporter.print(MISSING_GOLD_VALUE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + "-" + value2
+ SEPARATOR + "gold no value");
return false;
}
switch (gold.getNodeType())
{
case Node.DOCUMENT_NODE :
{
// Why don't we do anything here? -sc
}
break;
case Node.ELEMENT_NODE :
{
// Explicitly ignore attribute ordering
// TODO do we need to make this settable for testing purposes? -sc
NamedNodeMap goldAttrs = gold.getAttributes();
NamedNodeMap testAttrs = test.getAttributes();
if ((null != goldAttrs) && (null == testAttrs))
{
reporter.print(MISMATCH_ATTRIBUTE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + SEPARATOR
+ "test no attrs");
return false;
}
else if ((null == goldAttrs) && (null != testAttrs))
{
reporter.print(MISMATCH_ATTRIBUTE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + SEPARATOR
+ "gold no attrs");
return false;
}
int gn = goldAttrs.getLength();
int tn = testAttrs.getLength();
if (gn != tn)
{
reporter.print(MISMATCH_ATTRIBUTE + nodeTypeString(gold)
+ "-" + gn + SEPARATOR + nodeTypeString(test)
+ "-" + tn + SEPARATOR
+ "attribte count mismatch");
// TODO: add output of each set of attrs for comparisons
return false;
}
// TODO verify this checks the full list of attributes both ways,
// from gold->test and from test->gold -sc
for (int i = 0; i < gn; i++)
{
Attr goldAttr = (Attr) goldAttrs.item(i);
String goldAttrName = goldAttr.getName();
Node testAttr = testAttrs.getNamedItem(goldAttrName);
if (null == testAttr)
{
reporter.print(MISMATCH_ATTRIBUTE + nodeTypeString(gold)
+ "-" + goldAttrName + SEPARATOR
+ nodeTypeString(test) + SEPARATOR
+ "missing attribute on test");
return false;
}
if (!diff(goldAttr, testAttr, reporter, warning))
{
return false;
}
}
}
break;
case Node.CDATA_SECTION_NODE :{}
break;
case Node.ENTITY_REFERENCE_NODE :{}
break;
case Node.ATTRIBUTE_NODE :{}
break;
case Node.COMMENT_NODE :{}
break;
case Node.ENTITY_NODE :{}
break;
case Node.NOTATION_NODE :{}
break;
case Node.PROCESSING_INSTRUCTION_NODE :{}
break;
case Node.TEXT_NODE :{}
break;
default :{}
}
Node try2[] = new Node[2];
Node goldChild = gold.getFirstChild();
Node testChild = test.getFirstChild();
if (!basicChildCompare(goldChild, testChild, reporter, warning, try2))
return false;
goldChild = try2[0];
testChild = try2[1];
while (null != goldChild)
{
if (!diff(goldChild, testChild, reporter, warning))
return false;
goldChild = goldChild.getNextSibling();
testChild = testChild.getNextSibling();
if (!basicChildCompare(goldChild, testChild, reporter, warning,
try2))
return false;
goldChild = try2[0];
testChild = try2[1];
}
return true;
} // end of diff()
/**
* NEEDSDOC Method isWhiteSpace
*
*
* NEEDSDOC @param s
*
* NEEDSDOC (isWhiteSpace) @return
*/
boolean isWhiteSpace(String s)
{
int n = s.length();
for (int i = 0; i < n; i++)
{
if (!Character.isWhitespace(s.charAt(i)))
return false;
}
return true;
} // end of isWhiteSpace()
/**
* NEEDSDOC Method tryToAdvancePastWhitespace
*
*
* NEEDSDOC @param n
* NEEDSDOC @param reporter
* NEEDSDOC @param warning
* NEEDSDOC @param next
* NEEDSDOC @param which
*
* NEEDSDOC (tryToAdvancePastWhitespace) @return
*/
Node tryToAdvancePastWhitespace(Node n, PrintWriter reporter,
boolean[] warning, Node next[], int which)
{
if (n.getNodeType() == Node.TEXT_NODE)
{
String data = n.getNodeValue();
if (null != data)
{
if (isWhiteSpace(data))
{
warning[0] = true;
reporter.print(WHITESPACE_DIFF + " "); // TODO check the format of this; maybe use println -sc
n = n.getNextSibling();
next[which] = n;
}
}
}
return n;
} // end of tryToAdvancePastWhitespace()
/**
* NEEDSDOC Method basicChildCompare
*
*
* NEEDSDOC @param gold
* NEEDSDOC @param test
* NEEDSDOC @param reporter
* NEEDSDOC @param warning
* NEEDSDOC @param next
*
* NEEDSDOC (basicChildCompare) @return
*/
boolean basicChildCompare(Node gold, Node test, PrintWriter reporter,
boolean[] warning, Node next[])
{
next[0] = gold;
next[1] = test;
boolean alreadyTriedToAdvance = false;
if ((null != gold) && (null == test))
{
gold = tryToAdvancePastWhitespace(gold, reporter, warning, next,
0);
alreadyTriedToAdvance = true;
if ((null != gold) && (null == test))
{
reporter.print(MISSING_TEST_NODE + nodeTypeString(gold)
+ SEPARATOR + SEPARATOR
+ "missing node on test");
return false;
}
}
else if ((null == gold) && (null != test))
{
test = tryToAdvancePastWhitespace(test, reporter, warning, next,
1);
alreadyTriedToAdvance = true;
if ((null == gold) && (null != test))
{
reporter.print(MISSING_GOLD_NODE + SEPARATOR
+ nodeTypeString(test) + SEPARATOR
+ "missing node on gold");
return false;
}
}
if ((null != gold) && (gold.getNodeType() != test.getNodeType()))
{
Node savedGold = gold;
Node savedTest = test;
if (!alreadyTriedToAdvance)
{
gold = tryToAdvancePastWhitespace(gold, reporter, warning,
next, 0);
if (gold == savedGold)
{
test = tryToAdvancePastWhitespace(test, reporter,
warning, next, 1);
}
}
if ((null != gold) && (gold.getNodeType() != test.getNodeType()))
{
gold = savedGold;
test = savedTest;
reporter.print(MISMATCH_NODE + nodeTypeString(gold)
+ SEPARATOR + nodeTypeString(test) + SEPARATOR
+ "node type mismatch");
return false;
}
}
return true;
} // end of basicChildCompare()
/**
* Cheap-o text printout of a node. By Scott.
*
* NEEDSDOC @param n
*
* NEEDSDOC ($objectName$) @return
*/
String nodeTypeString(Node n)
{
String s;
switch (n.getNodeType())
{
case Node.DOCUMENT_NODE :
s = "DOCUMENT_NODE(" + n.getNodeName() + ")";
break;
case Node.ELEMENT_NODE :
s = "ELEMENT_NODE(" + n.getNodeName() + ")";
break;
case Node.CDATA_SECTION_NODE :
s = "CDATA_SECTION_NODE(" + n.getNodeName() + ")";
break;
case Node.ENTITY_REFERENCE_NODE :
s = "ENTITY_REFERENCE_NODE(" + n.getNodeName() + ")";
break;
case Node.ATTRIBUTE_NODE :
s = "ATTRIBUTE_NODE(" + n.getNodeName() + ")";
break;
case Node.COMMENT_NODE :
s = "COMMENT_NODE(" + n.getNodeName() + ")";
break;
case Node.ENTITY_NODE :
s = "ENTITY_NODE(" + n.getNodeName() + ")";
break;
case Node.NOTATION_NODE :
s = "NOTATION_NODE(" + n.getNodeName() + ")";
break;
case Node.PROCESSING_INSTRUCTION_NODE :
s = "PROCESSING_INSTRUCTION_NODE(" + n.getNodeName() + ")";
break;
case Node.TEXT_NODE :
s = "TEXT_NODE(" + n.getNodeName() + ")";
break;
default :
s = "UNKNOWN_NODE(" + n.getNodeName() + ")";
}
return s;
} // end of nodeTypeString()
/**
* Parameter: force use of URI's for Xerces 1.1.2 or leave filenames alone?
*/
protected boolean useURI = true;
/**
* NEEDSDOC Method parse
*
*
* NEEDSDOC @param filename
* NEEDSDOC @param reporter
* NEEDSDOC @param which
*
* NEEDSDOC (parse) @return
*/
Document parse(String filename, PrintWriter reporter, String which)
{
// Force filerefs to be URI's if needed: note this is independent of any other files
// Remember: this only applies to the wacky Xerces parser, which we're presumably
// using as our default DOMParser() below
String xercesFilename = filename;
if (useURI)
{
try
{
// Use static worker method to get the correct format
// Note: this is copied straight from Xalan 1.x's org.apache.xalan.xslt.Process
// TODO verify this is the most correct and simplest way to munge the filename
xercesFilename = getURLFromString(filename,
null).toExternalForm();
}
catch (Exception e)
{
reporter.print(WARNING + e.toString() + "\n");
}
}
String parseType = which + PARSE_TYPE + "[xml];";
DOMParser parser = new DOMParser();
Document doc = null;
try
{
// Use the Xerces-munged name specifically here!
parser.parse(new InputSource(xercesFilename));
doc = parser.getDocument();
}
catch (Throwable se)
{
reporter.print(WARNING + se.toString() + "\n");
parseType = which + PARSE_TYPE + "[html];";
try
{
// @todo need to find an HTML to DOM parser we can use!!!
// doc = someHTMLParser.parse(new InputSource(filename));
throw new RuntimeException("We need an HTML to DOM parser!");
}
catch (Exception e)
{
try
{
reporter.print(WARNING + e.toString() + "\n");
parseType = which + PARSE_TYPE + "[text];";
// Safer not to rely directly upon the DocumentImpl classes.
// DocumentImpl docImpl = new DocumentImpl();
// docImpl.appendChild(docElem);
// DocumentImpl docImpl =
// Instead, use the DOM Level 2 createDocument call.
// Obtaining the DOMImplementation is still nonportable;
// DOM Level 3 may address that.
Document docImpl =
DOMImplementationImpl.getDOMImplementation().createDocument(
null, "out", null);
Element docElem = docImpl.getDocumentElement();
// Parse as text, line by line
// Since we already know it should be text, this should
// work better than parsing by bytes.
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);
StringBuffer buffer = new StringBuffer();
for (;;)
{
String tmp = br.readLine();
if (tmp == null)
{
break;
}
buffer.append(tmp);
buffer.append("\n"); // Put in the newlines as well
}
Text tx = docImpl.createTextNode(buffer.toString());
// Note: will this always be a valid node? If we're parsing
// in as text, will there ever be cases where the diff that's
// done later on will fail becuase some really garbage-like
// text has been put into a node?
docElem.appendChild(tx);
doc = docImpl;
}
catch (Throwable throwable)
{
reporter.print(OTHER_ERROR + filename + SEPARATOR
+ "threw:" + throwable.toString() + "\n");
}
}
}
// Output a newline here for readability
reporter.print(parseType + "\n");
return doc;
} // end of parse()
/**
* Take a user string and try and parse XML, and also return the url.
* <p>Note: this needs to be revisited. It is only used to convert Strings
* that represent filenames into the proper URL format for Xerces 1.1x parser.</p>
* Note: this is copied straight from Xalan 1.x's org.apache.xalan.xslt.Process
*
* NEEDSDOC @param urlString
* NEEDSDOC @param base
*
* NEEDSDOC ($objectName$) @return
* @exception Exception thrown if we really really can't create the URL
*/
public static URL getURLFromString(String urlString, String base)
throws Exception
{
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)
{
// Below throw modified from original version
throw new Exception("Cannot create url for: "
+ urlString + " threw: "
+ e2.toString());
//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;
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/XHTFileCheckService.java
Index: XHTFileCheckService.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/>.
*/
/*
*
* XHTFileCheckService.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Uses an XML/HTML/Text diff comparator to check or diff two files.
* @author Shane_Curcuru@lotus.com
* @version $Id: XHTFileCheckService.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class XHTFileCheckService implements CheckService
{
/** XHTComparator tool to diff two files. */
protected XHTComparator comparator = new XHTComparator();
/** Stores last checkFile calls printed output. */
private StringWriter sw = null;
/**
* Compare two objects for equivalence, and return appropriate result.
* Implementers should provide the details of their "equals"
* algorithim in getCheckMethod().
* Note that the order of actual, reference is usually important
* important in determining the result.
* <li>Typically:
* <ul>any unexpected Exceptions thrown -> ERRR_RESULT</ul>
* <ul>actual does not exist -> FAIL_RESULT</ul>
* <ul>reference does not exist -> AMBG_RESULT</ul>
* <ul>actual is equivalent to reference -> PASS_RESULT</ul>
* <ul>actual is not equivalent to reference -> FAIL_RESULT</ul>
* </li>
*
* @param reporter to dump any output messages to
* @param actual (current) Object to check
* @param reference (gold, or expected) Object to check against
* @param description of what you're checking
* NEEDSDOC @param msg
* @return Reporter.*_RESULT code denoting status; each method may define
* it's own meanings for pass, fail, ambiguous, etc.
*/
public int check(Reporter reporter, Object actual, Object reference,
String msg)
{
if (!((actual instanceof File) & (reference instanceof File)))
{
// Must have File objects to continue
reporter.checkErr("XHTFileCheckService only takes files, with: "
+ msg);
return reporter.ERRR_RESULT;
}
File actualFile = (File) actual;
File referenceFile = (File) reference;
// Fail if Actual file doesn't exist or is 0 len
if ((!actualFile.exists()) || (actualFile.length() == 0))
{
reporter.checkFail(msg);
return reporter.FAIL_RESULT;
}
// Ambiguous if gold file doesn't exist or is 0 len
if ((!referenceFile.exists()) || (referenceFile.length() == 0))
{
reporter.checkAmbiguous(msg);
return Reporter.AMBG_RESULT;
}
sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
boolean warning[] = new boolean[1]; // TODO: should use this!
warning[0] = false;
boolean isEqual = false;
try
{
// Note calling order (gold, act) is different than checkFiles()
isEqual = comparator.compare(referenceFile.getCanonicalPath(),
actualFile.getCanonicalPath(), pw,
warning);
// Side effect: fills in sw with info about the comparison
}
catch (Exception e)
{
pw.println("comparator threw: " + e.toString());
isEqual = false;
}
pw.flush();
if (!isEqual)
{
// We fail, obviously!
reporter.checkFail(msg);
return Reporter.FAIL_RESULT;
}
else if (warning[0])
{
pw.println("comparator whitespace diff warning!");
pw.flush();
reporter.checkFail(msg);
return Reporter.FAIL_RESULT;
}
else
{
reporter.checkPass(msg);
return Reporter.PASS_RESULT;
}
}
/**
* Gets extended information about the last checkFiles call.
* @return String describing any additional info about the last two files that were checked
*/
public String getExtendedInfo()
{
if (sw != null)
return sw.toString();
else
return "XHTFileCheckService-no-info-available";
}
/**
* Description of algorithim used to check file equivalence.
*
* NEEDSDOC ($objectName$) @return
*/
public String getDescription()
{
return ("Uses an XML/HTML/Text diff comparator to check or diff two files.");
}
} // end of class XHTFileCheckService
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/XSLDirectoryIterator.java
Index: XSLDirectoryIterator.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/>.
*/
/*
*
* XSLDirectoryIterator.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import org.apache.qetest.xslwrapper.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL; // For optional URI/URLs instead of string filenames
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
// Try to catch this specific exception from the ProcessorWrapper, if it is thrown
import org.xml.sax.SAXException;
// /////////////////// HACK - added from Xalan1 org.apache.xalan.xslt.Process /////////////////////
import java.net.MalformedURLException;
//-------------------------------------------------------------------------
/**
* Sample Xalan test driver base that iterates over directories
* and xml/xsl file pairs.
* <p>This class provides generic support for iterating over directories full
* of xsl/xml file pairs, and sending them through the processor. Subclasses
* may override processSingleFile to call different variations of .process(...).</p>
* <p>Alternately, users may specify -fileList file.lst that contains listings
* of specific files to run (instead of iterating over the directories by following
* the appropriate Conformance rules).</p>
* <ul>initializes all members from XSLProcessorTestBase, plus
* <li>fileList</li>
* </ul>
* @todo improve file discovery - file execution paradigm
* @author Shane Curcuru
* @version $Id: XSLDirectoryIterator.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class XSLDirectoryIterator extends XSLProcessorTestBase
{
/**
* Convenience method to print out usage information.
* @author Shane Curcuru
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common options supported by XSLDirectoryIterator:\n"
+ " -" + OPT_FILELIST
+ " <name of listfile of tests to run>\n" + super.usage());
}
//-----------------------------------------------------
//-------- Constants for common input params --------
//-----------------------------------------------------
/**
* Parameter: Run a specific list of files, instead of iterating in dir.
* <p>Default: null, do normal ConformanceDir iteration.</p>
*/
public static final String OPT_FILELIST = "fileList";
/** NEEDSDOC Field fileList */
protected String fileList = "name_of_file.txt";
/**
* Token in xsl files signifying that an exception is expected.
* </p><!-- ExpectedException: 'put the .toString() representation of the exception here' --></p>
*/
public static final String EXPECTED_EXCEPTION = "ExpectedException:";
/**
* Returned from processSingleFile; signifies process completed without exceptions.
* <p>No other validation is performed (i.e. user must validate expected
* outputs themselves after this call returns).</p>
*/
public static final int PROCESS_OK = 1;
/**
* Returned from processSingleFile; signifies process threw an EXPECTED_EXCEPTION.
* <p>No other validation is performed (i.e. user must validate expected
* outputs, if any, themselves after this call returns).</p>
*/
public static final int GOT_EXPECTED_EXCEPTION = 2;
/**
* Returned from processSingleFile; signifies process threw a non-EXPECTED_EXCEPTION.
* <p>No other validation is performed (i.e. user must validate expected
* outputs, if any, themselves after this call returns, as well as ensuring
* that the test is still valid to continue).</p>
*/
public static final int UNEXPECTED_EXCEPTION = 3;
/** Convenience constant: .xml extension for input data file. */
protected static final String xmlExtension = ".xml";
/** Convenience constant: .xsl extension for stylesheet file. */
protected static final String xslExtension = ".xsl";
/** Convenience constant: .out extension for output result file. */
protected static final String outExtension = ".out";
/** Convenience constant: .log extension for logs and reporting files. */
protected static final String diagExtension = ".log";
/** Cheap-o way to set an indent on the processor. */
protected static final int NO_INDENT = -1; // an illegal value specifying 'default indent'
/** NEEDSDOC Field indentLevel */
protected int indentLevel = NO_INDENT;
/** Cheap-o diagnotic name manager. */
protected OutputNameManager diagNameMgr = null;
//-----------------------------------------------------
//-------- Worker methods to iterate over directories --------
//-----------------------------------------------------
/**
* Accesor for a processor wrapper.
* <ul>Wrapper must support the following operations:
* <li>Object createNewProcessor (String liaisonClassName) throws Exception</li>
* <li>long processToFile (String xmlSource, String xslStylesheet, String resultTree) throws Exception</li>
* <li>void reset()</li>
* <li>void setDiagnosticsOutput(java.io.PrintWriter pw)</li>
* </ul>
* <p>This allows tests to be agnostic to different flavors of processors.</p>
* @todo Update to new calls everywhere!
*/
protected org.apache.qetest.xslwrapper.ProcessorWrapper processorW;
/** Cheap-o benchmarking: total time spent in all process calls. */
long overallTime = 0;
/** Cheap-o benchmarking: total number of files processed. */
long overallFilesProcessed = 0;
/** Cheap-o benchmarking: total time spent in all process calls per directory. */
long dirTime = 0;
/** Cheap-o benchmarking: total number of files processed per directory. */
long dirFilesProcessed = 0;
// We also use XLTest's fields: reporter, flavor, liaison, diagnostics
// These would have to be parameterized to turn this class into an interface
/**
* Subclassed callback to provide info about the processor you're testing.
* <p>Override to return a string describing the specific version/flavor/etc.
* of the processor you're testing. Provides a default implementation that
* can be used if you wish. Called from logTestProps
* (which is called from processTestDir).</p>
* @return 'ProcessorVersion;' + getDescription()
*/
public String getDescription()
{
if (processorW != null)
{
// Auto-create a ProcessorWrapper as needed
createNewProcessor();
}
return "ProcessorVersion;" + processorW.getDescription();
}
/**
* Log out any version or system info.
* <p>Logs System.getProperties(), the testProps block, plus the provided string
* indicating the version info from the processor. Called from processTestDir.</p>
*/
public void logTestProps()
{
// Log out system/build info - use crit msg so it's always reported
reporter.logCriticalMsg(getDescription());
reporter.logHashtable(reporter.CRITICALMSG, System.getProperties(),
"System.getProperties");
reporter.logHashtable(reporter.CRITICALMSG, testProps, "testProps");
}
/**
* Iterate through our inputDir, going into subdirs and processing xml/xsl file pairs therein.
* <p>.</p>
* <p><B>NOTE:</B> It is the responsibility of the subclassed test to call
* createNewProcessor (or it's equivalent) before calling processTestDir!</p>
*/
public void processTestDir() // TODO change to processTests()
{
// NOTE: This method simply directly uses our/our parents instance variables:
// inputDir, reporter, category, outDir, goldDir, noErrTest,
// plus each of the benchmarking variables:
// overallTime, overallFilesProcessed, dirTime, dirFilesProcessed
// report out version info, properties, etc.
logTestProps();
// Ensure the inputDir is there - we must have a valid location for input files
File testDirectory = new File(inputDir);
if (!testDirectory.exists())
{
if (!lookForTestDir()) // attempt self-discovery of dirs
{
// Note: This might want to be inside of a testCase
reporter.checkErr("inputDir(" + testDirectory.getPath()
+ ") does not exist, aborting!");
return;
}
}
// We process tests in one of two different ways:
// - from a user specified -fileList
// - by iterating over all subdirs that follow the Conformance rules
String fileListFileName = testProps.getProperty(OPT_FILELIST);
if (fileListFileName != null)
{
// We're going to grab the list of files the user specified
// This should be a vector of XSLTestfileInfo objects, each one a test to run
// Currently, the readFileListFile method forces all files to be
// specified absolutely by the time it's done
reporter.logWarningMsg(
"-fileList property implies we ignore category and excludes!");
Vector list = readFileListFile(fileListFileName);
reporter.testCaseInit("Conformance Test of: fileList "
+ fileListFileName);
processFileList(list);
reporter.testCaseClose();
}
// TODO make the dir iteration below follow the same discovery - execution
// model as the fileList case above - requires re-writing the rest of this
// method as well as processSingleDir
else
{
// We're going to scan the test directory for subdirectories to iterate over
// Then for each subdir, we'll scan for files according to the
reporter.logInfoMsg("inputDir(" + testDirectory.getPath()
+ ") looking for valid subdirs...");
FilenameFilter dirFilter;
if ((category != null) && (category != ""))
{
// Filter on the directories we were asked for
// semi HACK - should implement a full list of categories, not just one
dirFilter = new ConformanceDirRules(category);
}
else
{ // Just use default filtering (skip dirs beginning with [x|X])
dirFilter = new ConformanceDirRules();
}
String dirNames[] = testDirectory.list(dirFilter);
if ((null == dirNames) || (dirNames.length <= 0))
{
// TODO should this be wrapped in a testCase?
reporter.checkFail("inputDir(" + testDirectory.getPath()
+ ") no valid subdirs found!");
return;
}
int nDirs = dirNames.length;
// For every subdirectory, check if we should run tests in it
for (int i = 0; i < nDirs; i++)
{
File subTestDir = new File(testDirectory, dirNames[i]);
// Convert all dir references to absolute ones, to get around
// potential problems with relative paths and test harnesses
// that change the current directory
// TODO: Check if we should use getCanonicalPath instead!
subTestDir = new File(subTestDir.getAbsolutePath());
if (null == subTestDir)
{
reporter.logWarningMsg("Could not find subdir: "
+ testDirectory.getPath()
+ File.pathSeparator
+ dirNames[i]);
continue;
}
File subOutDir = new File(outputDir, dirNames[i]);
subOutDir = new File(subOutDir.getAbsolutePath());
File subGoldDir = new File(goldDir, dirNames[i]);
subGoldDir = new File(subGoldDir.getAbsolutePath());
// Run our positive case tests
reporter.testCaseInit("Conformance Test of: " + dirNames[i]);
processSingleDir(subTestDir, subOutDir, subGoldDir, null); // using default file filter
if (dirFilesProcessed > 0)
{
// Only log these stats if perfLogging is set to true
String tmp =
testProps.getProperty(Reporter.OPT_PERFLOGGING);
if ((tmp != null) && tmp.equalsIgnoreCase("true"))
{
reporter.logStatistic(
reporter.STATUSMSG,
(dirTime / dirFilesProcessed), 0,
"Dir average time to process files in this dir");
reporter.logStatistic(
reporter.STATUSMSG,
(overallTime / overallFilesProcessed), 0,
"Running average time of dirs so far");
}
}
reporter.testCaseClose();
if (!noErrTest) // Note the double negative
{
// Run our negative, or 'err' case tests within this subdir
final String ERRDIRNAME = "err";
FilenameFilter errDirFilter =
new ConformanceDirRules(ERRDIRNAME);
String errDirNames[] = subTestDir.list(errDirFilter);
if ((null != errDirNames) && (errDirNames.length > 0))
{
// Hopefully, there's only the one 'err' directory!
for (int k = 0; k < errDirNames.length; k++)
{
File errTestDir = new File(subTestDir,
errDirNames[k]);
if (null == errTestDir)
{
reporter.logWarningMsg(
"Could not find errDir: "
+ subTestDir.getPath()
+ File.pathSeparator + errDirNames[i]);
continue;
}
// Optimization: if there are no files in the errDir, don't bother going there
FilenameFilter errFileFilter =
new ConformanceErrFileRules(dirNames[i]);
String anyErrNames[] =
errTestDir.list(errFileFilter);
if ((anyErrNames != null)
&& (anyErrNames.length > 0))
{
File errOutDir = new File(subOutDir,
errDirNames[k]);
File errGoldDir = new File(subGoldDir,
errDirNames[k]);
// Use special filter to look for parentName+"err"
reporter.testCaseInit(
"Conformance Test of errDir: "
+ errDirNames[k]);
processSingleDir(errTestDir, errOutDir,
errGoldDir, errFileFilter);
if (dirFilesProcessed > 0)
{
reporter.logStatistic(
reporter.STATUSMSG,
(dirTime / dirFilesProcessed), 0,
"Dir average time to process files in this dir");
reporter.logStatistic(
reporter.STATUSMSG,
(overallTime / overallFilesProcessed),
0, "Running average time of dirs so far");
}
reporter.testCaseClose();
} // of if ((anyErrNames != null).. Optimization
else
{
reporter.logStatusMsg(
"inputDir(" + errTestDir.getPath()
+ ") no 'err' files found");
}
} // of for (int k = 0...
} // of if (null != errDirNames)
else
{
reporter.logInfoMsg("inputDir("
+ testDirectory.getPath()
+ ") no 'err' subdirs found");
} // of if...else (null != errDirNames)
} // of if (runErrTests)
} // of for (int i = 0... 'For every subdirectory'
// Done with all dirs, report last statistic
if (overallFilesProcessed > 0)
{
// Only log these stats if perfLogging is set to true
String tmp = testProps.getProperty(Reporter.OPT_PERFLOGGING);
if ((tmp != null) && tmp.equalsIgnoreCase("true"))
{
reporter.logStatistic(
reporter.STATUSMSG,
(overallTime / overallFilesProcessed), 0,
"Overall average process time");
}
}
} // of if (fileListFileName != null)
}
/**
* Run one directory full of xsl/xml file pairs through the processor; virtually stateless.
* <p>This assumes the roots of each of test and out already exist.
* This then takes an existing test subdir, creates corresponding out and gold
* subdirs, and then processes all xsl/xml file pairs using processSingleFile().</p>
* <p>Default processing is provided for Conformance-style tests.</p>
* <p>Each subdirectory is treated like a test case.</p>
* <p>This method does not access the processorWrapper (or it's processor)
* in any way - thus is suitable for use in subclasses with overriden
* createNewProcessor() methods.</p>
* @param testDirectory specific dir with xml/xsl file pairs to iterate through
* @param outDirectory dir to put any output files in
* @param goldDirectory dir to look for expected gold files in
* @param filter filter for filenames to look for (null=default, name starts-with parent)
*/
public void processSingleDir(File testDirectory, File outDirectory,
File goldDirectory, FilenameFilter filter)
{
// Reset performance stuff first, so we don't double-report if we fail to run any tests here
dirTime = 0;
dirFilesProcessed = 0;
File[] requiredDirs = { testDirectory, outDirectory };
File[] otherDirs = { goldDirectory };
// testDirectory = 0, outDirectory = 1, goldDirectory = 2
File[] dirs = validateDirs(requiredDirs, otherDirs);
if (dirs == null) // also ensures that dirs[0] is non-null
{
reporter.checkFail(
"testDir or outDir do not exist, aborting test!");
return;
}
// Set a default filter (<name>*.xsl where <name>=<dir>) only if not already set
if (filter == null)
{
if ((excludes != null) && (excludes.length() > 1)) // Arbitrary check for non-null, non-blank string
{
filter = new ConformanceFileRules(excludes); // NOTE: changes caller's copy as well
reporter.logTraceMsg(
"Using default ConformanceFileRules with excludes: "
+ excludes);
}
else
{
filter = new ConformanceFileRules(); // NOTE: changes caller's copy as well
reporter.logTraceMsg("Using default ConformanceFileRules");
}
}
else
{ // NEEDSWORK: should only print this if it's also not already a ConformanceFileRules
reporter.logInfoMsg("Using custom fileFilter: "
+ filter.toString());
}
// Use the fileFilter to get only the names we want to test
String xslnames[] = dirs[0].list(filter);
if (null != xslnames)
{
int numXSLFiles = xslnames.length;
reporter.logInfoMsg("processOneDir(" + dirs[0].getPath()
+ ") with " + numXSLFiles
+ " potential .xsl files to test");
// Iterate over every xsl file found and check if we should test it
for (int k = 0; k < numXSLFiles; k++)
{
String xslName = xslnames[k];
// Find the root of the filename, less extension, and create .xml and .out versions of the name
// OPTIMIZATION? ConformanceDirRules probably ensure that we have a good name, so we may not need this.
int dotIndex = xslName.indexOf('.');
if (dotIndex > 0)
{
// Construct the various inputs to the LotusXSL processor, based on .xsl filename
String rootFileName = xslName.substring(0, dotIndex);
// Switch to CanonicalPaths which seem to be safer SC 28-Jun-00
String absXSLName = null;
try
{
absXSLName = dirs[0].getCanonicalPath()
+ File.separatorChar + xslName;
}
catch (IOException ioe1)
{
absXSLName = dirs[0].getAbsolutePath()
+ File.separatorChar + xslName;
}
String absXMLName = null;
try
{
absXMLName = dirs[0].getCanonicalPath()
+ File.separatorChar + rootFileName
+ xmlExtension;
}
catch (IOException ioe2)
{
absXMLName = dirs[0].getAbsolutePath()
+ File.separatorChar + rootFileName
+ xmlExtension;
}
if (dirs[1] == null)
{
// Provide some sort of default TODO is this the best cross-platform default?
dirs[1] = new File("\badOutDir");
reporter.logErrorMsg(
"outDir(" + outDirectory
+ ") is bad - resetting to \badOutDir");
}
String absOutName = null;
try
{
absOutName = dirs[1].getCanonicalPath()
+ File.separatorChar + rootFileName
+ outExtension;
}
catch (IOException ioe3)
{
absOutName = dirs[1].getAbsolutePath()
+ File.separatorChar + rootFileName
+ outExtension;
}
if (dirs[2] == null)
{
// Provide some sort of default
dirs[2] = new File("\badGoldDir");
reporter.logErrorMsg(
"goldDir(" + goldDirectory
+ ") is bad - resetting to \badGoldDir");
}
String absGoldName = null;
try
{
absGoldName = dirs[2].getCanonicalPath()
+ File.separatorChar + rootFileName
+ outExtension;
}
catch (IOException ioe3)
{
absGoldName = dirs[2].getAbsolutePath()
+ File.separatorChar + rootFileName
+ outExtension;
}
// Sanity check - see if files exist (not strictly needed?)
File xslF = new File(absXSLName);
File xmlF = new File(absXMLName);
if (xslF.exists() && xmlF.exists())
{
reporter.logTraceMsg("About to test:"
+ xmlF.getName() + " with:"
+ xslF.getName() + " into:"
+ absOutName);
}
else
{
reporter.logWarningMsg("Files may not exist:"
+ absXMLName + " or:"
+ absXSLName);
}
// Actually run the xsl/xml file pair through the processor
// Note subclasses may override this to do different kinds of processing
// FUTUREWORK: put this switch in a method, so subclasses can ovverride
// to also do different kinds of validation!
switch (processSingleFile(absXMLName, absXSLName,
absOutName))
{
case PROCESS_OK :
int res = fileChecker.check(reporter,
new File(absOutName),
new File(absGoldName),
xslF.getName()
+ " output comparison");
// ((XLTestReporter)reporter).checkFiles(new File(absOutName), new File(absGoldName), xslF.getName() + " output comparison");
// If we're using an appropriate fileChecker,
// get extra info on a fail
if (res == reporter.FAIL_RESULT)
{
String tmp = fileChecker.getExtendedInfo();
if (tmp != null)
reporter.logArbitrary(reporter.INFOMSG, tmp);
else
reporter.logTraceMsg(
"getFileChecker().getExtendedInfo() not available");
}
break;
case GOT_EXPECTED_EXCEPTION :
reporter.checkPass(xslF.getName()
+ " got expected exception");
break;
case UNEXPECTED_EXCEPTION :
reporter.checkFail(xslF.getName()
+ " got unexpected exception");
break;
}
} // of if (dotIndex > 0)
else
{
reporter.logWarningMsg("Problem with xsl filename: "
+ xslName);
}
} // of for (int k = 0...
} // of if (null != xslnames)
else
{
reporter.logWarningMsg("Could not find any xsl files in: "
+ dirs[0].getPath());
}
// update overall statistics
overallTime += dirTime;
overallFilesProcessed += dirFilesProcessed;
}
// HEY - need a quintuple: xml, xsl, out, gold, options
/**
* Run a list of specific files through the processor; virtually stateless.
* <p>The file names are assumed to be fully specified, and we assume
* the corresponding directories exist.</p>
* <p>This method does not access the processorWrapper (or it's processor)
* in any way - thus is suitable for use in subclasses with overriden
* createNewProcessor() methods.</p>
* @param testDirectory specific dir with xml/xsl file pairs to iterate through
* @param outDirectory dir to put any output files in
* @param goldDirectory dir to look for expected gold files in
* @param vector of XSLTestfileInfo objects of (xslFile, xmlFile, outFile, goldFile, options)
*
* NEEDSDOC @param fileList
*/
public void processFileList(Vector fileList)
{
// Reset performance stuff first, so we don't double-report if we fail to run any tests here
dirTime = 0;
dirFilesProcessed = 0;
// String xslnames[] = dirs[0].list(filter);
if (null == fileList)
{
// No files, no testing - report an error and return
reporter.logErrorMsg("Blank fileList - nothing to test!");
return;
}
// Now just go through the list and process each set
int numXSLFiles = fileList.size();
reporter.logInfoMsg("processFileList() with " + numXSLFiles
+ " potential .xsl files to test");
// Iterate over every xsl file found and check if we should test it
for (int ctr = 0; ctr < numXSLFiles; ctr++)
{
// If the object is not an XSLTestfileInfo, assume it's a string to create one with
XSLTestfileInfo fileSet = null;
try
{
fileSet = (XSLTestfileInfo) fileList.elementAt(ctr);
}
catch (ClassCastException cce)
{
fileSet =
new XSLTestfileInfo((String) fileList.elementAt(ctr), "");
// If this line fails, too bad!
}
// Sanity check - see if files exist (not strictly needed?)
File xslF = new File(fileSet.inputName);
File xmlF = new File(fileSet.xmlName);
if (xslF.exists() && xmlF.exists())
{
reporter.logTraceMsg("About to test:" + fileSet.xmlName
+ " with:" + fileSet.inputName
+ " into:" + fileSet.outputName);
}
else
{
reporter.logWarningMsg("Files may not exist:"
+ fileSet.xmlName + " or:"
+ fileSet.inputName);
}
// Actually run the xsl/xml file pair through the processor
// Note subclasses may override this to do different kinds of processing
// FUTUREWORK: put this switch in a method, so subclasses can ovverride
// to also do different kinds of validation!
switch (processSingleFile(fileSet.xmlName, fileSet.inputName,
fileSet.outputName))
{
case PROCESS_OK :
int res = fileChecker.check(reporter,
new File(fileSet.outputName),
new File(fileSet.goldName),
xslF.getName()
+ " output comparison");
// ((XLTestReporter)reporter).checkFiles(new File(fileSet.outputName), new File(fileSet.goldName), xslF.getName() + " output comparison");
// If we're using an appropriate fileChecker,
// get extra info on a fail
if (res == reporter.FAIL_RESULT)
{
String tmp = fileChecker.getExtendedInfo();
if (tmp != null)
reporter.logArbitrary(reporter.INFOMSG, tmp);
else
reporter.logTraceMsg(
"getFileChecker().getExtendedInfo() not available");
}
break;
case GOT_EXPECTED_EXCEPTION :
reporter.checkPass(xslF.getName()
+ " got expected exception");
break;
case UNEXPECTED_EXCEPTION :
reporter.checkFail(xslF.getName()
+ " got unexpected exception");
break;
}
} // of while...
// update overall statistics
overallTime += dirTime;
overallFilesProcessed += dirFilesProcessed;
}
/**
* Run one xsl/xml file pair through the processor.
* <p>May be overriden by subclasses to do different kinds of processing -
* mainly variations of the process(...) APIs.</p>
* <p>XSLDirectoryIterator provides a default implementation that
* is appropriate for use with Conformance tests.</p>
* <p>processSingleFile should do all processing required to transform the XMLName,
* via the XSLName, into an OutName file on disk. It returns a status denoting
* what happend during the processing.</p>
* <p>Should increment dirTotalTime and dirFilesProcessed.</p>
* <p>processSingleFile() and createNewProcessor() both rely on using the
* same semantics to use the processor (or processorWrapper); thus if a
* subclass overrides one, you should probably override the other.</p>
* <p>Due to changes Jun-00 in Xerces 1.1.2; checks XLTest.useURI to see
* if we can use unadulterated filenames or have to use URI's.</p>
* @author Shane Curcuru
* @todo update to use XSLTestfileInfo objects instead
* @param XMLName path\filename of XML data file
* @param XSLName path\filename of XSL Stylesheet file
* @param OutName path\filename of desired output file
* @return int status - pass, fail, expected exception or unexpected exception
*/
public int processSingleFile(String XMLName, String XSLName,
String OutName)
{
long fileTime = ProcessorWrapper.ERROR;
try
{
// Reset the indent level each time, to ensure the process uses it (it may get reset() below)
if (indentLevel > NO_INDENT)
{
reporter.logTraceMsg("processSingleFile() set indent "
+ indentLevel);
processorW.setIndent(indentLevel);
}
// Force filerefs to be URI's if needed
if (useURI)
{
// Use this static convenience method; returns a URL; convert to String via toExternalForm()
XMLName = getURLFromString(XMLName, null).toExternalForm();
XSLName = getURLFromString(XSLName, null).toExternalForm();
// HACK (end)- replicate this code locally, since we may test Xalan2 which doesn't have this!
// Note: Currently 28-Jun-00, the output of files is handled differently, so
// we do NOT want to convert those. Subject to change, however.
reporter.logTraceMsg("processSingleFile() useURI: "
+ XSLName);
}
fileTime = processorW.processToFile(XMLName, XSLName, OutName);
if (fileTime != ProcessorWrapper.ERROR)
{
dirTime += fileTime;
dirFilesProcessed++;
reporter.logTraceMsg("processSingleFile(" + XSLName
+ ") no exceptions; time " + fileTime);
}
else
{
// Do not increment performance counters if there's an error
reporter.logWarningMsg("processSingleFile(" + XSLName
+ ") returned ERROR code!");
}
processorW.reset();
}
// Catch SAXExceptions and check if they're expected; restart to be safe
catch (SAXException sax)
{
reporter.logStatusMsg("processSingleFile(" + XSLName
+ ") threw: " + sax.toString());
int retVal = checkExpectedException(sax, XSLName, OutName);
createNewProcessor(); // Should be configurable!
return retVal;
}
// Catch general Exceptions, check if they're expected, and restart
catch (Exception e)
{
reporter.logStatusMsg("processSingleFile(" + XSLName
+ ") threw: " + e.toString());
int retVal = checkExpectedException(e, XSLName, OutName);
createNewProcessor();
return retVal;
}
// Catch any Throwable, check if they're expected, and restart
catch (Throwable t)
{
reporter.logStatusMsg("processSingleFile(" + XSLName
+ ") threw: " + t.toString());
int retVal = checkExpectedException(t, XSLName, OutName);
createNewProcessor();
return retVal;
}
return PROCESS_OK;
}
/**
* Worker method to validate expected exception text.
* <p>Logs message and creates new processor if useDefaultProcessor;
* also performs basic validation of .toString() of exception.</p>
* <p>Does not store any state; suitable for use in interface.</p>
* @author Shane Curcuru
* @todo update to use XSLTestfileInfo objects instead
* @param expected exception that was caught above
* @param filename of XSL test file where 'ExpectedException:' may be
* @param filename of output file , optional for future use
*
* NEEDSDOC @param ee
* NEEDSDOC @param testName
* NEEDSDOC @param outName
* @return status, as one of PROCESS_OK, GOT_EXPECTED_EXCEPTION, UNEXPECTED_EXCEPTION
*/
protected int checkExpectedException(Throwable ee, String testName,
String outName)
{
// Is this exception the one we expected? Assume not
boolean gotExpected = false;
// Read in the testName file to see if it's expecting something
try
{
FileReader fr = new FileReader(testName);
BufferedReader br = new BufferedReader(fr);
// NEEDSWORK: should we optimize and only check the first xx num lines?
for (;;)
{
String inbuf = br.readLine();
if (inbuf == null)
break; // end of file, break out and return default (false)
int idx = inbuf.indexOf(EXPECTED_EXCEPTION);
if (idx <= 0)
continue; // not on this line, keep going
// The expected exception.getMessage is the rest of the line, trimmed
// Note that there's actually a " -->" at the end of the line probably,
// but we'll ignore that by using .startsWith()
String expExc =
inbuf.substring((idx + EXPECTED_EXCEPTION.length()),
inbuf.length()).trim();
if (expExc.startsWith(ee.toString()))
{
gotExpected = true; // equal, they pass
break;
}
else
{
// Not equal, so keep looking for another flavor
continue;
}
} // end for (;;)
}
catch (java.io.IOException ioe)
{
reporter.logWarningMsg("checkExpectedException() threw: "
+ ioe.toString());
gotExpected = false;
}
return (gotExpected ? GOT_EXPECTED_EXCEPTION : UNEXPECTED_EXCEPTION);
}
/**
* Ask the wrapper to construct a processor, with optional diagnostic logs.
* <p>this worker method is called from within processSingleFile as well as
* various places within subclassed tests.</p>
* <p>processSingleFile() and createNewProcessor() both rely on using the
* same semantics to use the processor (or processorWrapper); thus if a
* subclass overrides one, you should probably override the other.</p>
* @return status - OK if successfull, false if some error occoured
*/
protected boolean createNewProcessor()
{
if ((flavor == null) || (flavor.equals("")))
{
return false;
}
if (processorW == null)
{
// Create the specific subclass for desired flavor
processorW = ProcessorWrapper.getWrapper(flavor);
if (processorW == null)
{
// Something must have gone wrong with the wrapper
reporter.logErrorMsg(
"createNewProcessor() failed with flavor: " + flavor);
}
}
try
{
Object temp = processorW.createNewProcessor(liaison);
if (temp == null)
{
reporter.logErrorMsg(
"createNewProcessor() got null for processor");
}
}
catch (Exception e)
{
reporter.logErrorMsg("createNewProcessor() threw: "
+ e.toString());
reporter.logThrowable(reporter.CRITICALMSG, e,
"createNewProcessor() threw: ");
return false;
}
if (diagnostics != null)
{
if (diagNameMgr == null)
{
// Create a new name manager, hardcode the .log extension just because
diagNameMgr = new OutputNameManager(diagnostics, ".log");
}
try
{
processorW.setDiagnosticsOutput(
new PrintWriter(new FileWriter(diagNameMgr.nextName())));
reporter.logInfoMsg("createNewProcessor() new diagnostics = "
+ diagNameMgr.currentName());
}
catch (IOException ioe)
{
reporter.logWarningMsg(
"createNewProcessor() could not create new diagnostics = "
+ diagNameMgr.currentName());
return false;
}
}
// Apply an optional indent if asked; this needs to be documented!
// @todo this name conflicts with Logger.OPT_INDENT: we should
// consider changing this one (which isn't a great property
// anyway with new serializer models)
String idt = testProps.getProperty("indent", null);
// Only attempt to apply the indent if we think there's really a value there
if ((idt != null) && (!idt.equals("")))
{
int temp = NO_INDENT;
try
{
temp = Integer.parseInt(idt);
}
catch (NumberFormatException numEx)
{
temp = NO_INDENT; // Make sure we don't try to use an illegal value
reporter.logWarningMsg(
"createNewProcessor() failed to set indent " + idt);
}
if (temp > NO_INDENT)
{
indentLevel = temp;
processorW.setIndent(indentLevel);
reporter.logTraceMsg("createNewProcessor() set indent "
+ idt);
}
else
{
reporter.logTraceMsg(
"createNewProcessor() did not set indent " + idt);
}
}
else
{
reporter.logTraceMsg(
"createNewProcessor() skipping blank/null indent, now "
+ indentLevel);
}
return true;
}
/**
* Read in a line-oriented file specifying a list of files to test.
* <p>File format is pretty simple:</p>
* <ul>
* <li># beginning a line is a comment</li>
* <li># if <b>first</b> line in file has 'relative' anywhere, paths are
* relative to testDir, outDir, etc.</li>
* <li># (default is assuming all paths are absolute)</li>
* <li># rest of lines are space delimited filenames and options</li>
* <li>xslName xmlName outName goldName options options options...</li>
* <li><b>Note:</b> see {@link XSLTestfileInfo XSLTestfileInfo} for
* details on how the file lines are parsed!</li>
* </ul>
* <p>Most items are optional, but not having them may result in validation oddities</p>
* @param String; name of the file
*
* NEEDSDOC @param fileName
* @return Vector of XSLTestfileInfo objects, null if any error
*/
public Vector readFileListFile(String fileName)
{
final String COMMENT_CHAR = "#";
final String ABSOLUTE = "absolute";
final String RELATIVE = "relative";
final String UNSPECIFIED_FILENAME = "UNSPECIFIED_FILENAME";
// Verify the file is there and we can open it
File f = new File(fileName);
if (!f.exists())
{
reporter.logErrorMsg("FileListFile: " + fileName
+ " does not exist!");
return null;
}
FileReader fr = null;
BufferedReader br = null;
Vector vec = new Vector();
String line = null;
try
{
br = new BufferedReader(new FileReader(f));
line = br.readLine();
}
catch (IOException ioe)
{
reporter.logErrorMsg("FileListFile: " + fileName + " threw: "
+ ioe.toString());
return null;
}
// Read in the file line by line
if (line == null)
{
reporter.logErrorMsg("FileListFile: " + fileName
+ " appears to be blank!");
return null;
}
// Check if the first line is a comment *and* has 'relative'
// Note default is relative paths to testDir/testDir/outDir/goldDir
boolean isRelative = false;
if ((line.startsWith(COMMENT_CHAR)) && (line.indexOf(RELATIVE) > 0))
{
isRelative = true;
}
// Load each line into an XSLTestfileInfo object
for (;;)
{
// Skip any lines beginning with # comment char or that are blank
if ((!line.startsWith(COMMENT_CHAR)) && (line.length() > 0))
{
// Create a testInfo object and initialize it with the line's contents
XSLTestfileInfo testInfo = new XSLTestfileInfo(line,
UNSPECIFIED_FILENAME);
// Avoid spurious passes when output & gold both not specified
if (testInfo.goldName.equals(UNSPECIFIED_FILENAME))
{
testInfo.goldName += "-gold";
}
// Add it to our vector
vec.addElement(testInfo);
}
// Read next line and loop
try
{
line = br.readLine();
}
catch (IOException ioe2)
{
// Just force us out of the loop; if we've already read part of the file, fine
reporter.logWarningMsg("FileListFile: " + fileName
+ " threw: " + ioe2.toString());
break;
}
if (line == null)
break;
}
if (vec.size() == 0)
{
reporter.logErrorMsg("FileListFile: " + fileName
+ " did not have any non-comment lines!");
return null;
}
// Now, munge the paths if asked to
if (isRelative)
{
XSLTestfileInfo basePaths = new XSLTestfileInfo();
// xml,xsl are in testDir, out is in outDir, gold is in goldDir
StringTokenizer st = new StringTokenizer(inputDir + "\t"
+ inputDir + "\t"
+ outputDir + "\t"
+ goldDir, "\t");
basePaths.load(st, "undefined");
mungeListPaths(basePaths, vec);
}
if (debug)
{
// Cheap-o debugging for this stuff
for (int ctr = 0; ctr < vec.size(); ctr++)
{
reporter.logTraceMsg(
"vec[" + ctr + "] = "
+ ((XSLTestfileInfo) vec.elementAt(ctr)).dump());
}
}
reporter.logTraceMsg("readFileListFile(" + fileName + ") isRelative="
+ isRelative + ", size=" + vec.size());
return vec;
}
/**
* Munge relative paths to start from testDir,testDir,outDir,goldDir.
* <p>Changes caller's copy of the vector. options field is left untouched</p>
* @param XSLTestfileInfo base directories for each member
* @param Vector of XSLTestfileInfos to munge
*
* NEEDSDOC @param base
* NEEDSDOC @param vec
*/
public void mungeListPaths(XSLTestfileInfo base, Vector vec)
{
// TODO!!!
reporter.logCriticalMsg(
"mungeListPaths NOT IMPLEMENTED! Only absolute ones are done");
}
/**
* Validate our test, output, and gold dirs; return test dir.
* <p>If any optional dir cannot be created, it's array entry will be null.</p>
* @author Shane Curcuru
* @param array of directories that must previously exist
* @param array of optional directories; if they do not exist they'll be created
*
* NEEDSDOC @param requiredDirs
* NEEDSDOC @param optionalDirs
* @return array of file objects, null if any error
*/
public File[] validateDirs(File[] requiredDirs, File[] optionalDirs)
{
if ((requiredDirs == null) || (optionalDirs == null))
{
return null;
}
File[] dirs = new File[(requiredDirs.length + optionalDirs.length)];
int ctr = 0;
try
{
for (int ir = 0; ir < requiredDirs.length; ir++)
{
reporter.logTraceMsg("validateDirs(" + requiredDirs[ir]
+ ") loop");
if (!requiredDirs[ir].exists())
{
if (!requiredDirs[ir].mkdirs())
{
reporter.logErrorMsg("validateDirs("
+ requiredDirs[ir]
+ ") does not exist!");
return null;
}
else
{
reporter.logTraceMsg("validateDirs("
+ requiredDirs[ir]
+ ") was created");
}
}
dirs[ctr] = requiredDirs[ir];
ctr++;
}
for (int iopt = 0; iopt < optionalDirs.length; iopt++)
{
reporter.logTraceMsg("validateDirs(" + optionalDirs[iopt]
+ ") loop");
if (!optionalDirs[iopt].exists())
{
if (!optionalDirs[iopt].mkdirs())
{
reporter.logWarningMsg("validateDirs("
+ optionalDirs[iopt]
+ ") could not be created");
dirs[ctr] = null;
}
else
{
reporter.logTraceMsg("validateDirs("
+ optionalDirs[iopt]
+ ") was created");
dirs[ctr] = optionalDirs[iopt];
}
}
else
{ // It does previously exist, so copy it over
dirs[ctr] = optionalDirs[iopt];
}
ctr++;
}
}
catch (Exception e)
{
reporter.logErrorMsg("validateDirs threw: " + e.toString());
e.printStackTrace(); // NEEDSWORK
return null;
}
return (dirs);
}
/**
* Attempt to find a testDir if provided one doesn't exist.
* Presumably if we have a known directory structure, we can
* implement a simple search that will look for the
* 'conformancetest' directory, whether it's below or above
* us by one directory level. For the terminally lazy who
* don't bother specifying inputDir.
* @return status - OK if we found it, false otherwise
*/
public boolean lookForTestDir()
{
// Not implemented
return false;
}
// /////////////////// HACK - added from Xalan1 org.apache.xalan.xslt.Process /////////////////////
/**
* Take a user string and try and parse XML, and also return
* the url. Needed for Xerces 1.2 builds.
* @todo replace this with simpler code, better logging
*
* 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 XSLDirectoryIterator
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/XSLProcessorTestBase.java
Index: XSLProcessorTestBase.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/>.
*/
/*
*
* XSLProcessorTestBase.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.Vector;
//------------------------------------------------------------------------
/**
* Base class for all Xalan tests.
* <p>XSLProcessorTestBase defines a number of common fields
* that most tests will use in addition to FileBasedTest. It
* also defaults to using an XMLFileLogger as well as a
* ConsoleLogger, if none have been specified.</p>
* <ul>initializes all members from FileBasedTest, plus
* <li>category</li>
* <li>excludes</li>
* <li>liaison</li>
* <li>flavor</li>
* <li>diagnostics</li>
* <li>noReuse</li>
* <li>precompile</li>
* <li>runErr</li>
* </ul>
* @author Shane_Curcuru@lotus.com
* @version $Id: XSLProcessorTestBase.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class XSLProcessorTestBase extends FileBasedTest
{
/**
* Convenience method to print out usage information.
* @author Shane Curcuru
*
* NEEDSDOC ($objectName$) @return
*/
public String usage()
{
return ("Common options supported by XSLProcessorTestBase:\n"
+ " -" + OPT_CATEGORY
+ " <name of single subdir within testDir to run>\n"
+ " -" + OPT_EXCLUDES
+ " <list;of;specific file.xsl tests to skip>\n" + " -"
+ OPT_LIAISON + " <liaisonClassName>\n" + " -"
+ OPT_FLAVOR
+ " <xalan|lotusxsl|xt|etc... - which kind of Processor to test>\n"
+ " -" + OPT_DIAGNOSTICS
+ " <root filename for diagnostics output>\n" + " -"
+ OPT_NOREUSE
+ " (will force recreate processor each time)\n" + " -"
+ OPT_PRECOMPILE
+ " (will use precompiled stylesheet, if applicable)\n"
+ " -" + OPT_NOERRTEST
+ " (will skip running 'err' tests, if applicable)\n"
+ super.usage());
}
//-----------------------------------------------------
//-------- Constants for common input params --------
//-----------------------------------------------------
/**
* Parameter: Only run a single subcategory of the tests.
* <p>Default: blank, runs all tests - supply the directory name
* of a subcategory to run just that set.</p>
*/
public static final String OPT_CATEGORY = "category";
/** NEEDSDOC Field category */
protected String category = null;
/**
* Parameter: Reuse/reset processor between cases or create a new one each time?
* <p>Default: false - create one processor and call reset between tests.</p>
*/
// TODO: Move to directoryiterator
public static final String OPT_NOREUSE = "noReuse";
/** NEEDSDOC Field noReuse */
protected boolean noReuse = true;
/**
* Parameter: What parser liaison or option to use?
* <p>Default: null, Whichever default your processor uses.</p>
*/
// TODO: Move to directoryiterator
public static final String OPT_LIAISON = "liaison";
/** NEEDSDOC Field liaison */
protected String liaison = null;
/**
* Parameter: What flavor of ProcessorWrapper to use: trax|xalan1|other?
* <p>Default: trax.</p>
*/
public static final String OPT_FLAVOR = "flavor";
/** NEEDSDOC Field flavor */
protected String flavor = "trax";
/**
* Parameter: Name of output file for diagnostics/error logs?
* <p>Default: null, do not use one</p>
*/
// TODO: Move to directoryiterator
public static final String OPT_DIAGNOSTICS = "diagnostics";
/** NEEDSDOC Field diagnostics */
protected String diagnostics = null;
/**
* Parameter: Should we try to use a precompiled stylesheet?
* <p>Default: false, no (not applicable in all cases).</p>
*/
public static final String OPT_PRECOMPILE = "precompile";
/** NEEDSDOC Field precompile */
protected boolean precompile = false;
/**
* Parameter: Should we run any 'err' subdir tests or not?
* <p>Default: false (i.e. <b>do</B> run error tests by default).</p>
* @todo update, this is clumsy (reverse double negative option)
*/
public static final String OPT_NOERRTEST = "noErrTest";
/** NEEDSDOC Field noErrTest */
protected boolean noErrTest = false;
/**
* Parameter: force use of URI's for Xerces 1.1.2 or leave filenames alone?
* <p>Default: true, use URI's</p>
* @todo update, this is clumsy
*/
public static final String OPT_USEURI = "useURI";
/** NEEDSDOC Field useURI */
protected boolean useURI = true;
/**
* Parameter: Which CheckService should we use for XML output Files?
* <p>Default: org.apache.qetest.SimpleFileCheckService.</p>
*/
public static final String OPT_FILECHECKER = "fileChecker";
/** NEEDSDOC Field fileCheckerName */
protected String fileCheckerName =
"org.apache.qetest.SimpleFileCheckService";
/** NEEDSDOC Field fileChecker */
protected CheckService fileChecker = null;
/**
* Parameter: Should we exclude any specific test files?
* <p>Default: null (no excludes; otherwise specify semicolon delimited list like 'axes01.xsl;bool99.xsl').</p>
*/
public static final String OPT_EXCLUDES = "excludes";
/** NEEDSDOC Field excludes */
protected String excludes = null;
/**
* Default constructor - initialize testName, Comment.
*/
public XSLProcessorTestBase()
{
// Only set them if they're not set
if (testName == null)
testName = "XSLProcessorTestBase.defaultName";
if (testComment == null)
testComment = "XSLProcessorTestBase.defaultComment";
}
//-----------------------------------------------------
//-------- Implement Test/TestImpl methods --------
//----------------------------------------------------
/**
* Initialize this test - called once before running testcases.
* <p>Use the loggers field to create some loggers in a Reporter.</p>
* @author Shane_Curcuru@lotus.com
*
* NEEDSDOC @param p
*
* NEEDSDOC ($objectName$) @return
*/
public boolean preTestFileInit(Properties p)
{
// Ensure we have an XMLFileLogger if we have a logName
String logF = testProps.getProperty(Logger.OPT_LOGFILE);
if ((logF != null) && (!logF.equals("")))
{
// We should ensure there's an XMLFileReporter
String r = testProps.getProperty(Reporter.OPT_LOGGERS);
if (r == null)
{
testProps.put(Reporter.OPT_LOGGERS,
"org.apache.qetest.XMLFileLogger");
}
else if (r.indexOf("XMLFileLogger") <= 0)
{
testProps.put(Reporter.OPT_LOGGERS,
r + Reporter.LOGGER_SEPARATOR
+ "org.apache.qetest.XMLFileLogger");
}
}
// Ensure we have a ConsoleLogger unless asked not to
// @todo improve and document this feature
String noDefault = testProps.getProperty("noDefaultReporter");
if (noDefault == null)
{
// We should ensure there's an XMLFileReporter
String r = testProps.getProperty(Reporter.OPT_LOGGERS);
if (r == null)
{
testProps.put(Reporter.OPT_LOGGERS,
"org.apache.qetest.ConsoleLogger");
}
else if (r.indexOf("ConsoleLogger") <= 0)
{
testProps.put(Reporter.OPT_LOGGERS,
r + Reporter.LOGGER_SEPARATOR
+ "org.apache.qetest.ConsoleLogger");
}
}
// Pass our properties block directly to the reporter
// so it can use the same values in initialization
// A Reporter will auto-initialize from the values
// in the properties block
setReporter(new Reporter(p));
reporter.addDefaultLogger(); // add default logger if needed
reporter.testFileInit(testName, testComment);
// Fixup some paths to be absolute, see method comments for @todo
fixupPaths();
// Create a file-based CheckService for later use
if (fileChecker == null)
{
try
{
Class fClass = Class.forName(fileCheckerName);
fileChecker = (CheckService) fClass.newInstance();
reporter.logTraceMsg("Using file-based CheckService: "
+ fileChecker);
}
catch (Exception e)
{
reporter.logWarningMsg("Failed to create an instance of "
+ fileCheckerName + ": "
+ e.toString());
// This could cause NullPointerExceptions for those
// tests that rely on our fileChecker...
}
}
return true;
}
// use other implementations from FileBasedTest
//-----------------------------------------------------
//-------- Initialize our common input params --------
//-----------------------------------------------------
/**
* Set our instance variables from a Properties file.
* Calls super.initializeFromProperties() to get defaults.
* @author Shane Curcuru
* @param Properties block to set name=value pairs from
*
* NEEDSDOC @param props
* @return status - true if OK, false if error.
* @todo improve error checking, if needed
*/
public boolean initializeFromProperties(Properties props)
{
debugPrintln("XSLProcessorTestBase.initializeFromProperties(" + props
+ ")");
boolean b = super.initializeFromProperties(props);
category = props.getProperty(OPT_CATEGORY, category);
if (category != null)
testProps.put(OPT_CATEGORY, category);
liaison = props.getProperty(OPT_LIAISON, liaison);
if (liaison != null)
testProps.put(OPT_LIAISON, liaison);
flavor = props.getProperty(OPT_FLAVOR, flavor);
if (flavor != null)
testProps.put(OPT_FLAVOR, flavor);
fileCheckerName = props.getProperty(OPT_FILECHECKER, fileCheckerName);
if (fileCheckerName != null)
testProps.put(OPT_FILECHECKER, fileCheckerName);
excludes = props.getProperty(OPT_EXCLUDES, excludes);
if (excludes != null)
testProps.put(OPT_EXCLUDES, excludes);
diagnostics = props.getProperty(OPT_EXCLUDES, diagnostics);
if (diagnostics != null)
testProps.put(OPT_EXCLUDES, diagnostics);
String prec = props.getProperty(OPT_PRECOMPILE);
if ((prec != null) && prec.equalsIgnoreCase("true"))
{
precompile = true;
testProps.put(OPT_PRECOMPILE, "true");
}
String noet = props.getProperty(OPT_NOERRTEST);
if ((noet != null) && noet.equalsIgnoreCase("true"))
{
noErrTest = true;
testProps.put(OPT_NOERRTEST, "true");
}
String uURI = props.getProperty(OPT_USEURI);
if ((uURI != null) && uURI.equalsIgnoreCase("false"))
{
useURI = false;
testProps.put(OPT_USEURI, "false");
}
return b;
}
/**
* Sets the provided fields with data from an array, presumably
* from the command line.
* <p>Overridden from FileBasedTest, but calls super.() to
* get default properties.</p>
* @author Shane Curcuru
*
* NEEDSDOC @param args
* @return status - true if OK, false if error.
*/
public boolean initializeFromArray(String[] args)
{
debugPrintln("XSLProcessorTestBase.initializeFromArray(" + args
+ ")");
// Read in command line args and setup internal variables
String optPrefix = "-";
int nArgs = args.length;
if (nArgs == 0)
{
System.out.println("ERROR: you must supply required arguments!");
return false;
}
// Our parent class already read in the properties file
// override values from properties file
for (int k = 0; k < nArgs; k++)
{
if (args[k].equalsIgnoreCase(optPrefix + OPT_LOAD))
{
if (++k >= nArgs)
{
System.out.println(
"ERROR: must supply properties filename for: "
+ optPrefix + OPT_LOAD);
return false;
}
load = args[k];
try
{
// Load named file into our properties block
FileInputStream fIS = new FileInputStream(load);
Properties p = new Properties();
p.load(fIS);
initializeFromProperties(p);
}
catch (Exception e)
{
System.out.println(
"ERROR: loading properties file failed: " + load);
e.printStackTrace();
return false;
}
break;
}
}
// Now read in the rest of the command line
// @todo cleanup loop to be more table-driven
for (int i = 0; i < nArgs; i++)
{
if (args[i].equalsIgnoreCase(optPrefix + OPT_CATEGORY))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_CATEGORY);
return false;
}
category = args[i];
testProps.put(OPT_CATEGORY, category);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_LIAISON))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_LIAISON);
return false;
}
liaison = args[i];
testProps.put(OPT_LIAISON, liaison);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_FLAVOR))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_FLAVOR);
return false;
}
flavor = args[i];
testProps.put(OPT_FLAVOR, flavor);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_DIAGNOSTICS))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_DIAGNOSTICS);
return false;
}
diagnostics = args[i];
testProps.put(OPT_DIAGNOSTICS, diagnostics);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_FILECHECKER))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_FILECHECKER);
return false;
}
fileCheckerName = args[i];
testProps.put(OPT_FILECHECKER, fileCheckerName);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_EXCLUDES))
{
if (++i >= nArgs)
{
System.out.println("ERROR: must supply arg for: "
+ optPrefix + OPT_EXCLUDES);
return false;
}
excludes = args[i];
testProps.put(OPT_EXCLUDES, excludes);
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_NOREUSE))
{
noReuse = false;
testProps.put(OPT_NOREUSE, "false");
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_PRECOMPILE))
{
precompile = true;
testProps.put(OPT_PRECOMPILE, "true");
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_NOERRTEST))
{
noErrTest = true;
testProps.put(OPT_NOERRTEST, "true");
continue;
}
if (args[i].equalsIgnoreCase(optPrefix + OPT_USEURI))
{
useURI = false; // Toggle from default of true; ugly but I'm in a hurry
testProps.put(OPT_USEURI, "false");
continue;
}
}
// Be sure to ask our superclass to read it's options as well!
return super.initializeFromArray(args, false);
}
//-----------------------------------------------------
//-------- Other useful and utility methods --------
//-----------------------------------------------------
/**
* Worker method to fixup pathing for diagnostics.
* @todo - this is a hack, we may not even need it
* @author Shane Curcuru
*/
public void fixupPaths()
{
// Convert all dir references to absolute ones, to get around
// potential problems with relative paths and test harnesses
// that change the current directory
// Try getCanonicalPath first; otherwise default to getAbsolutePath()
// @todo also implement logFile
if (diagnostics != null)
{
File tempF = new File(diagnostics);
try
{
diagnostics = tempF.getCanonicalPath();
}
catch (IOException ioe1)
{
diagnostics = tempF.getAbsolutePath();
}
reporter.logTraceMsg(OPT_DIAGNOSTICS + " reset to absolute: "
+ diagnostics);
}
}
/**
* Main worker method to run test from the command line.
* Test subclasses generally need not override.
* <p>This is primarily provided to make subclasses implementations
* of the main method as simple as possible: in general, they
* should simply do:
* <code>
* public static void main (String[] args)
* {
* TestSubClass app = new TestSubClass();
* app.doMain(args);
* }
* </code>
* @author Shane Curcuru
*
* NEEDSDOC @param args
*/
public void doMain(String[] args)
{
debugPrintln("XSLProcessorTestBase.doMain(" + args + ")");
// Initialize any instance variables from the command line
// OR specified properties block
if (!initializeFromArray(args))
{
System.err.println("ERROR in usage:");
System.err.println(usage());
// Don't use System.exit, since that will blow away any containing harnesses
return;
}
// Also pass along the command line, in case someone has
// specific code that's counting on this
testProps.put(MAIN_CMDLINE, args);
runTest(testProps);
}
/**
* Main method to run test from the command line.
* @author Shane Curcuru
* <p>Test subclasses <b>must</b> override, obviously.
* Only provided here for debugging.</p>
*
* NEEDSDOC @param args
*/
public static void main(String[] args)
{
XSLProcessorTestBase app = new XSLProcessorTestBase();
app.debug = true; // HACK
app.doMain(args);
}
} // end of class XSLProcessorTestBase
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/XSLTestfileInfo.java
Index: XSLTestfileInfo.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/>.
*/
/*
*
* XSLTestfileInfo.java
*
*/
package org.apache.qetest.xsl;
import org.apache.qetest.TestfileInfo;
import java.util.Properties;
import java.util.StringTokenizer;
/**
* Simple data-holding class specifying info about one 'testfile'.
* <p>Convenience class for XSL Processor testing, includes
* additional fields and overrides some methods to change order
* of initializer strings.</p>
* <ul>Fields read in new order:
* <li>inputName - xsl stylesheet</li>
* <li>xmlName - xml data file <b>new</b></li>
* <li>outputName - for results of transform</li>
* <li>goldName</li>
* <li>description</li>
* <li>author</li>
* <li>options</li>
* </ul>
* @author Shane Curcuru
* @version $Id: XSLTestfileInfo.java,v 1.1 2000/11/01 23:26:57 curcuru Exp $
*/
public class XSLTestfileInfo extends TestfileInfo
{
/** Name of the input XML data file. */
public String xmlName = null;
/** NEEDSDOC Field XMLNAME */
public static final String XMLNAME = "xmlName";
/** No-arg constructor leaves everything null. */
public XSLTestfileInfo(){}
/**
* Initialize members from name=value pairs in Properties block.
* Default value for each field is null.
* @param Properties block to initialize from
*
* NEEDSDOC @param p
*/
public XSLTestfileInfo(Properties p)
{
load(p);
}
/**
* Pass in a StringTokenizer-default-delimited string to initialize members.
* <p>Members are read in order: inputName <i>xmlName</i> outputName goldName
* author description options...
* default value for each field is null</p>
* @param String to initialize from
*
* NEEDSDOC @param inputStr
*/
public XSLTestfileInfo(String inputStr)
{
StringTokenizer st = new StringTokenizer(inputStr);
load(st, null);
}
/**
* Pass in a StringTokenizer-default-delimited string to initialize members.
* <p>Members are read in order: inputName <i>xmlName</i> outputName goldName
* author description options...
* default value for each field is user-specified String</p>
* @param String to initialize from
* @param String to use as default for any un-specified value
*
* NEEDSDOC @param inputStr
* NEEDSDOC @param defaultVal
*/
public XSLTestfileInfo(String inputStr, String defaultVal)
{
StringTokenizer st = new StringTokenizer(inputStr);
load(st, defaultVal);
}
/**
* Pass in a specified-delimited string to initialize members.
* <p>Members are read in order: inputName <i>xmlName</i> outputName goldName
* author description options...
* default value for each field is user-specified String</p>
* @param String to initialize from
* @param String to use as default for any un-specified value
* @param String to use as separator for StringTokenizer
*
* NEEDSDOC @param inputStr
* NEEDSDOC @param defaultVal
* NEEDSDOC @param separator
*/
public XSLTestfileInfo(String inputStr, String defaultVal,
String separator)
{
StringTokenizer st = new StringTokenizer(inputStr, separator);
load(st, defaultVal);
}
/**
* Worker method to initialize members.
*
* NEEDSDOC @param st
* NEEDSDOC @param defaultVal
*/
public void load(StringTokenizer st, String defaultVal)
{
// Fill in as many items as are available; default the value otherwise
// Note that order is important!
if (st.hasMoreTokens())
inputName = st.nextToken();
else
inputName = defaultVal;
// Override from base class: put the xmlName next
if (st.hasMoreTokens())
xmlName = st.nextToken();
else
xmlName = defaultVal;
if (st.hasMoreTokens())
outputName = st.nextToken();
else
outputName = defaultVal;
if (st.hasMoreTokens())
goldName = st.nextToken();
else
goldName = defaultVal;
if (st.hasMoreTokens())
author = st.nextToken();
else
author = defaultVal;
if (st.hasMoreTokens())
description = st.nextToken();
else
description = defaultVal;
if (st.hasMoreTokens())
{
options = st.nextToken();
// For now, simply glom all additional tokens into the options, until the end of string
// Leave separated with a single space char for readability
while (st.hasMoreTokens())
{
options += " " + st.nextToken();
}
}
else
options = defaultVal;
}
/**
* Initialize members from name=value pairs in Properties block.
* Default value for each field is null.
* @param Properties block to initialize from
*
* NEEDSDOC @param p
*/
public void load(Properties p)
{
inputName = p.getProperty(INPUTNAME);
xmlName = p.getProperty(XMLNAME); // Override from base class
outputName = p.getProperty(OUTPUTNAME);
goldName = p.getProperty(GOLDNAME);
author = p.getProperty(AUTHOR);
description = p.getProperty(DESCRIPTION);
options = p.getProperty(OPTIONS);
}
/**
* Cheap-o debugging: return tab-delimited String of all our values.
*
* NEEDSDOC ($objectName$) @return
*/
public String dump()
{
return (inputName + '\t' + xmlName // Override from base class
+ '\t' + outputName + '\t' + goldName + '\t' + author + '\t'
+ description + '\t' + options);
}
}
1.1 xml-xalan/test/java/src/org/apache/qetest/xsl/package.html
Index: package.html
===================================================================
<html>
<title>XSL-TEST general XSLT package.</title>
<body>
<p>This package contains XSLT testing base classes and utilities, and a generic test driver.</p>
<dl>
<dt><b>Author: </b></dt><dd><a href="mailto:shane_curcuru@lotus.com">Shane_Curcuru@lotus.com</a></dd>
<dt><b>Program(s) Under Test: </b></dt>
<dd><a href="http://xml.apache.org/xalan-j" target="_top">Xalan-J 2.x XSLT Processor</a></dd>
<dd><a href="http://xml.apache.org/xalan" target="_top">Xalan-J 1.x XSLT Processor</a></dd>
<dd><a href="http://xml.apache.org/xalan-c" target="_top">Xalan-C 1.x XSLT Processor</a></dd>
</dl>
<p>This package includes base classes and utilities, as well as several
generic test drivers that use {@link org.apache.qetest.xslwrapper.ProcessorWrapper ProcessorWrappers}
to process stylesheets. Classes in this package must not depend directly
on any Xalan interfaces, only on the ProcessorWrapper interface.<p>
<ul>Current utilities include:
<li>Logging* - implementations of XSLT-related listeners
and the like that log to our Reporter.</li>
<li>XHTFileCheckService, XHTComparator - checks equivalence of
two File objects by parsing either as XML, HTML, or text. Note
the HTML parsing is unimplemented - we need a good HTML->DOM
parser we can use in Apache - any suggestions?</li>
<li>XSLTestfileInfo - simple extension of TestfileInfo to
add xmlName member.</li>
<li>XSLDirectoryIterator - simple implementation that processes
xsl/xml file pairs from a fileList or over a directory tree,
automatically comparing the result files with a known good
or 'gold' reference tree of outputs.</li>
<li>XSLProcessorTestBase - adds useful XSLT processing
utilities, etc. from FileTestBase: including flags like
-preprocess, -flavor, -category, etc. Most xsl and trax
package Test scripts derive from this class.</li>
</ul>
<ul>Current tests include:
<li>ConformanceTest - generic test driver, including some
FilenameFilters. This essentially uses the XSLDirectoryIterator
for everything.</li>
<li>PerformanceTest - test driver that iterates repeatedly and
reports memory and timing info.</li>
<li>CConformanceTest - generic test driver that constructs a
command line and then shells out to execute TestXSLT.exe, which
is from the Xalan-C build. This allows basic comparisons of
results from the Java versions with the C++ versions.</li>
</ul>
</body>
</html>
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/LotusXSLWrapper.java
Index: LotusXSLWrapper.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/>.
*/
/*
*
* LotusXSLWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.util.Vector;
import java.io.PrintWriter;
// The LotusXSL implementation
import com.lotus.xsl.XSLProcessor;
import com.lotus.xsl.XSLTInputSource;
import com.lotus.xsl.XSLTResultTarget;
// For the versioning string from Xalan
import org.apache.xalan.xslt.XSLProcessorVersion;
/**
* Implementation of a ProcessorWrapper for LotusXSL.
* @author Shane Curcuru
* @version $Id: LotusXSLWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public class LotusXSLWrapper extends ProcessorWrapper
{
/** No-op Ctor for the LotusXSL-only wrapper. */
public LotusXSLWrapper(){}
/** Reference to current processor - LotusXSL flavor - convenience method. */
protected com.lotus.xsl.XSLProcessor processor = null;
/**
* NEEDSDOC Method getLotusXSLProcessor
*
*
* NEEDSDOC (getLotusXSLProcessor) @return
*/
public com.lotus.xsl.XSLProcessor getLotusXSLProcessor()
{
return processor;
}
/**
* Construct a processor of the appropriate flavor, optionally specifying a liaison.
* <p>May throw exceptions related to the creating of a new processor.</p>
* <ul>LotusXSL supports five liaisons:
* <li>org.apache.xalan.xpath.dtm.DTMLiaison (from Xalan)</li>
* <li>org.apache.xalan.xpath.xdom.XercesLiaison (from Xalan)</li>
* <li>com.lotus.xml.xml4j2dom.XML4JLiaison4dom (from XML4J 2.0.15)</li>
* <li>com.lotus.xml.xml4j2tx.XML4JLiaison (from XML4J 2.0.15)</li>
* <li>com.lotus.xml.xml4j.ProcessXSL (from XML4J 1.1.16)</li>
* </ul>
* @param liaisonClassName [optional] if non-null & non-blank, classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception // Cover all exception cases
{
// Cleanup any prior objects
cleanup();
if (liaisonClassName != null)
processor = new XSLProcessor(liaisonClassName);
else
processor = new XSLProcessor();
p = (Object) processor;
// Return here; will be null if error or exception raised
return (p);
}
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor and possibly it's common options
*/
public String getDescription()
{
if (processor == null)
{
return ("ERROR: must call createNewProcessor first from: "
+ getDescription());
}
else
{
// StringBuffer buf = new StringBuffer(XSLProcessorVersion.PRODUCT);
StringBuffer buf = new StringBuffer("LotusXSL"); // Note that LotusXSL does not override the PRODUCT field
buf.append(";");
buf.append(XSLProcessorVersion.LANGUAGE);
buf.append(";");
buf.append(XSLProcessorVersion.S_VERSION);
buf.append(";");
buf.append(processor.getXMLProcessorLiaison());
return buf.toString();
}
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception // Cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
com.lotus.xsl.XSLTInputSource xml =
new com.lotus.xsl.XSLTInputSource(xmlSource);
com.lotus.xsl.XSLTInputSource xsl =
new com.lotus.xsl.XSLTInputSource(xslStylesheet);
com.lotus.xsl.XSLTResultTarget result =
new com.lotus.xsl.XSLTResultTarget(resultFile);
// Begin timing the whole process
startTime = System.currentTimeMillis();
processor.process(xml, xsl, result);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Preprocess a stylesheet and set it into the processor, based on string inputs.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
com.lotus.xsl.StylesheetRoot sRoot;
com.lotus.xsl.XSLTInputSource xsl =
new com.lotus.xsl.XSLTInputSource(xslStylesheet);
// Begin timing loading the stylesheet
startTime = System.currentTimeMillis();
sRoot = processor.processStylesheet(xsl); // side effect: also sets the stylesheet
endTime = System.currentTimeMillis();
stylesheetReady = true;
return (endTime - startTime);
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* @param xmlSource name of source XML file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Ensure we (apparently) have already processed a stylesheet
if (!stylesheetReady)
throw new java.lang.IllegalStateException(
"You must call preProcessStylesheet first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
com.lotus.xsl.XSLTInputSource xml =
new com.lotus.xsl.XSLTInputSource(xmlSource);
com.lotus.xsl.XSLTResultTarget result =
new com.lotus.xsl.XSLTResultTarget(resultFile);
// Begin timing the whole process
startTime = System.currentTimeMillis();
processor.process(xml, null, result);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Reset the state.
* <p>This needs to be called after a process() call is invoked,
* if the processor is to be used again; at least for xalan and lotusxsl flavors.</p>
*/
public void reset()
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.reset();
stylesheetReady = false;
}
/**
* Set diagnostics output PrintWriter.
*
* NEEDSDOC @param pw
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setDiagnosticsOutput(pw);
}
/**
* Set the indent level of the processor.
*
* NEEDSDOC @param i
*/
public void setIndent(int i)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.getXMLProcessorLiaison().setIndent(i);
}
/**
* Set a String name=value param in the processor, if applicable.
*
* NEEDSDOC @param key
* NEEDSDOC @param expression
*/
public void setStylesheetParam(String key, String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setStylesheetParam(key, expression);
}
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @todo Needs Implementation: namespace is currently <b>ignored!</b>
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public void setStylesheetParam(String namespace, String key,
String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setStylesheetParam(key, expression);
}
/** Worker method to cleanup any internal state. */
private void cleanup()
{
processor = null;
p = null;
stylesheetReady = false;
}
} // end of class LotusXSLWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/ProcessorWrapper.java
Index: ProcessorWrapper.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/>.
*/
/*
*
* ProcessorWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Helper class to adapt or wrap instances of xsl processors.
* <p>Abstract class defining basic processor actions and a
* static method to create specific flavors of wrappers. This
* serves as a simple way to abstract the act of processing an XML
* data file with an XSL stylesheet into an output file. Thus
* test classes can be written that can operate on any type of
* wrappered processor.</p>
* <p>Basic API's for processing also return a long denoting the
* number of milliseconds taken during the 'interesting portions'
* of that operation. Note that it is <b>very</b> important that
* implementing classes clearly document exactly what is being
* timed in their implementations, and the ways that they are
* implementing the process (SAX, DOM, etc.)</p>
* @author Shane Curcuru
* @version $Id: ProcessorWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public abstract class ProcessorWrapper
{
//-----------------------------------------------------
//-------- Worker methods implemented by subclassed wrappers --------
//-----------------------------------------------------
/**
* Construct a processor of the appropriate flavor, optionally
* specifying a liaison or other option.
* <p>May throw exceptions related to the creating of a new processor.
* Subclasses must set the value of (Object)p in this method and return it.</p>
* <p>Note that not all processors may use liaisons in the same manner.</p>
* @param liaisonClassName [optional] if non-null & non-blank,
* classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
* @todo revisit: see if liaisonClassName should be genericized
*
* @throws java.lang.Exception
*/
public abstract Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception; // Cover all exception cases
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor
*/
public abstract String getDescription();
/** Reference to actual current processor object. */
protected Object p = null;
/**
* Reference to actual current processor object.
*
* NEEDSDOC ($objectName$) @return
*/
public Object getProcessor()
{
return p;
}
/** If we think the current processor has a preprocessed stylesheet ready. */
protected boolean stylesheetReady = false;
/**
* If we think the current processor has a preprocessed stylesheet ready.
*
* NEEDSDOC ($objectName$) @return
*/
public boolean getStylesheetReady()
{
return stylesheetReady;
}
/** Return value when an error occours from process* methods. */
public static final long ERROR = -1L;
//-----------------------------------------------------
//-------- Processing methods implemented by subclassed wrappers --------
//-----------------------------------------------------
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public abstract long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception; // Cover all exception cases
/**
* Preprocess a stylesheet and set it into the processor.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public abstract long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception; // should cover all exception cases
/**
* Process the xmlSource using a preProcessStylesheet to produce the resultFile.
* @param xmlSource name of source XML file
* @param resultFile name of output file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public abstract long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception; // should cover all exception cases
/**
* Set a String name=value param in the processor, if applicable.
* @param key name of the param
* @param expression value of the param
*/
public abstract void setStylesheetParam(String key, String expression);
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public abstract void setStylesheetParam(String namespace, String key,
String expression);
/** Reset the state of the processor, if applicable. */
public abstract void reset();
/**
* Set a diagnostics output PrintWriter, if applicable.
* @param pw PrintWriter to dump diagnostic or error output
*/
public abstract void setDiagnosticsOutput(java.io.PrintWriter pw);
/**
* Set the indent level of the processor, if applicable.
* <p>Note that the default is to let the processor decide the indent
* level (and/or if it should indent or not). If you set it explicitly,
* then 0 == no indent or equivalent, >=1 == indent to that level.</p>
* @param i indent level
*/
public abstract void setIndent(int i);
//-----------------------------------------------------
//-------- Factory static class methods --------
//-----------------------------------------------------
/**
* Currently known 'good' list of implemented wrappers.
* <p>Allows specification of a simple name for each wrapper,
* so clients don't necessarily have to know the full classname.</p>
* <ul>Where:
* <li>key = String simple name = xalan|trax|etc...</li>
* <li>value = String full classname</li>
* <li>Or, optionally:</li>
* <li>value = String full classname;property=value</li>
* <li>Supports: See ProcessorWrapper.properties</li>
* </ul>
* <p>As a hack, some values can be 'overloaded' by specifying
* an optional system property name = value pair after a semicolon
* in the value. This will be stripped off and set into the System
* properties before creating the wrapper.</p>
*/
protected static Properties wrapperMapper = null;
/** Static initializer for wrapperMapper. */
static
{
wrapperMapper = new Properties();
try
{
InputStream is = ProcessorWrapper.class.getResourceAsStream(
"ProcessorWrapper.properties");
wrapperMapper.load(is);
is.close();
}
catch (IOException ioe)
{
System.err.println("Loading ProcessorWrapper.properties threw: "
+ ioe.toString());
ioe.printStackTrace();
}
}
;
/**
* Accessor for our wrapperMapper.
*
* NEEDSDOC ($objectName$) @return
*/
public static final Properties getDescriptions()
{
return wrapperMapper;
}
/** Separators for specially wrapped classes and their properties. */
public static final String WRAPPER_SEPARATOR = ";";
/** Separators for specially wrapped classes and their properties. */
public static final String PROPERTY_SEPARATOR = "=";
/**
* Create a wrapper of a specific flavor.
* <p>When using a 'mapped' flavor, will also set the requested
* System property before creating the wrapper class itself.</p>
* @param flavor name of a wrapper class; simple names or FQCN's
* @return a ProcessorWrapper of the desired type; null if error
*/
public static final ProcessorWrapper getWrapper(String flavor)
{
// Attempt to lookup the flavor: if found, use the
// value we got, otherwise default to the same value
String className = null;
className = wrapperMapper.getProperty(flavor, flavor);
// Strip off any optional properties and set them
int pos = className.indexOf(WRAPPER_SEPARATOR);
if (pos > 0)
{
// Rip off the property part, and save it
String prop = className.substring(pos + 1);
className = className.substring(0, pos);
// Separate into property=value
int pos2 = prop.indexOf(PROPERTY_SEPARATOR);
String val = ""; // default to blank string
if (pos2 > 0)
{
val = prop.substring(pos2 + 1);
prop = prop.substring(0, pos2);
}
// Set the property into the system
// This will presumably be used by the specific
// wrapper class later for some purpose
System.getProperties().put(prop, val); // Applet may throw SecurityException
}
// Constuct one of the asked-for Wrappers
Class wClass = null;
ProcessorWrapper wrapper = null;
try
{
wClass = Class.forName(className);
wrapper = (ProcessorWrapper) wClass.newInstance();
}
catch (Exception e)
{
System.err.println("Exception creating flavor(" + className
+ ") threw: " + e.toString());
e.printStackTrace();
}
return wrapper;
}
} // end of class ProcessorWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/ProcessorWrapper.properties
Index: ProcessorWrapper.properties
===================================================================
# wrapperMapper lookups for ProcessorWrapper implementations
xalan=org.apache.qetest.xslwrapper.XalanWrapper
xalan1=org.apache.qetest.xslwrapper.XalanWrapper
# for now, simply use TRAX interface for xalan2
xalan2=org.apache.qetest.xslwrapper.TraxWrapper
trax=org.apache.qetest.xslwrapper.TraxWrapper
# anything after the semicolon; is set as a System property by ProcessorWrapper
trax.s2s=org.apache.qetest.xslwrapper.TraxWrapper;trax.wrapper.type=sax-to-sax
trax.s2t=org.apache.qetest.xslwrapper.TraxWrapper;trax.wrapper.type=sax-to-stream
trax.d2d=org.apache.qetest.xslwrapper.TraxWrapper;trax.wrapper.type=dom-to-dom
trax.filter=org.apache.qetest.xslwrapper.TraxWrapper;trax.wrapper.type=as-xml-filter
# Wrappers implemented for comparison purposes
lotusxsl=org.apache.qetest.xslwrapper.LotusXSLWrapper
xt=org.apache.qetest.xslwrapper.XTWrapper
saxon=org.apache.qetest.xslwrapper.SaxonWrapper
saxon.s2s=org.apache.qetest.xslwrapper.SaxonWrapper;trax.wrapper.type=sax-to-sax
saxon.d2d=org.apache.qetest.xslwrapper.SaxonWrapper;trax.wrapper.type=dom-to-dom
saxon.filter=org.apache.qetest.xslwrapper.SaxonWrapper;trax.wrapper.type=as-xml-filter
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/SaxonWrapper.class
<<Binary file>>
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/SaxonWrapper.java
Index: SaxonWrapper.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/>.
*/
/*
*
* SaxonWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.io.PrintWriter; // currently only used in unimplemented setDiagnosticsOutput
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
// For utility method source
import java.net.URL;
import java.net.MalformedURLException;
// Needed SAX classes
import org.xml.sax.*;
// A Saxon-specific TRaX-like wrapper
// NOTE: package name subject to change!
import com.icl.saxon.*;
import com.icl.saxon.trax.*;
import com.icl.saxon.trax.serialize.*; // Note: Saxon does not provide
// real implementations of serializers
// so this needs work!
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
// For the DOM examples we use Xerces
import org.apache.xerces.parsers.DOMParser;
import org.apache.xerces.dom.DocumentImpl;
/**
* Implementation of a ProcessorWrapper for the TRax interface of SAXON 5.5.1.
* @todo share constants between TraxWrapper, SaxonWrapper
* @todo document how we perform various types of transforms
* @author Shane Curcuru
* @version $Id: SaxonWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public class SaxonWrapper extends ProcessorWrapper
{
/** No-op Ctor for the SAXON TRAX interface wrapper. */
public SaxonWrapper(){}
/** Reference to current processor - SAXON flavor - convenience method. */
protected com.icl.saxon.trax.Processor processor = null;
/**
* NEEDSDOC Method getTraxProcessor
*
*
* NEEDSDOC (getTraxProcessor) @return
*/
public com.icl.saxon.trax.Processor getTraxProcessor()
{
return (processor);
}
/** A preprocessed stylesheet that we're saving. */
private Templates savedStylesheet = null;
/** Whatever parameters the user has set. */
private Hashtable params = null;
/** Which type of transform we should perform. */
protected int transformType = DEFAULT_TYPE;
/** Constants for different types of transforms. */
public static final String FILE_TO_FILE = "file-to-file";
/** NEEDSDOC Field FILE_TO_FILE_TYPE */
public static final int FILE_TO_FILE_TYPE = 1;
/** NEEDSDOC Field DOM_TO_DOM */
public static final String DOM_TO_DOM = "dom-to-dom";
/** NEEDSDOC Field DOM_TO_DOM_TYPE */
public static final int DOM_TO_DOM_TYPE = 2;
/** NEEDSDOC Field SAX_TO_SAX */
public static final String SAX_TO_SAX = "sax-to-sax";
/** NEEDSDOC Field SAX_TO_SAX_TYPE */
public static final int SAX_TO_SAX_TYPE = 3;
/** NEEDSDOC Field SAX_TO_STREAM */
public static final String SAX_TO_STREAM = "sax-to-stream";
/** NEEDSDOC Field SAX_TO_STREAM_TYPE */
public static final int SAX_TO_STREAM_TYPE = 4;
/** NEEDSDOC Field DOM_TO_STREAM */
public static final String DOM_TO_STREAM = "dom-to-stream";
/** NEEDSDOC Field DOM_TO_STREAM_TYPE */
public static final int DOM_TO_STREAM_TYPE = 5;
/** NEEDSDOC Field STREAM_TO_DOM */
public static final String STREAM_TO_DOM = "stream-to-dom";
/** NEEDSDOC Field STREAM_TO_DOM_TYPE */
public static final int STREAM_TO_DOM_TYPE = 6;
/** NEEDSDOC Field AS_XML_FILTER */
public static final String AS_XML_FILTER = "as-xml-filter";
/** NEEDSDOC Field AS_XML_FILTER_TYPE */
public static final int AS_XML_FILTER_TYPE = 7;
/** NEEDSDOC Field DEFAULT_TRANSFORM */
public static final String DEFAULT_TRANSFORM = FILE_TO_FILE;
/** NEEDSDOC Field DEFAULT_TYPE */
public static final int DEFAULT_TYPE = FILE_TO_FILE_TYPE;
/**
* Mapping of transform types to integer constants.
*/
protected static Hashtable typeMap = null;
// Static class initializer for our typeMap
static
{
typeMap = new Hashtable();
typeMap.put(FILE_TO_FILE, new Integer(FILE_TO_FILE_TYPE));
typeMap.put(DOM_TO_DOM, new Integer(DOM_TO_DOM_TYPE));
typeMap.put(SAX_TO_SAX, new Integer(SAX_TO_SAX_TYPE));
typeMap.put(SAX_TO_STREAM, new Integer(SAX_TO_STREAM_TYPE));
typeMap.put(DOM_TO_STREAM, new Integer(DOM_TO_STREAM_TYPE));
typeMap.put(STREAM_TO_DOM, new Integer(STREAM_TO_DOM_TYPE));
typeMap.put(AS_XML_FILTER, new Integer(AS_XML_FILTER_TYPE));
}
;
/** Constants for system properties, etc.. */
public static final String TRAX_PROCESSOR = "trax.processor";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = TRAX_PROCESSOR + "."
+ XSLT;
/** NEEDSDOC Field ORG_XML_SAX_DRIVER */
public static final String ORG_XML_SAX_DRIVER = "org.xml.sax.driver";
/** NEEDSDOC Field DEFAULT_PROCESSOR */
public static final String DEFAULT_PROCESSOR = "com.icl.saxon.StyleSheet"; // SAXON 5.5.1
/** NEEDSDOC Field DEFAULT_PARSER */
public static final String DEFAULT_PARSER =
"org.apache.xerces.parsers.SAXParser"; // TODO which parser to use?
/** NEEDSDOC Field TRAX_WRAPPER_TYPE */
public static final String TRAX_WRAPPER_TYPE = "trax.wrapper.type";
/**
* Construct a processor of the appropriate flavor, optionally specifying a liaison.
* <p>May throw exceptions related to the creating of a new processor.</p>
* <p>Note liaison support is not really implemented - a TODO item.</p>
* <p>This method defaults the "trax.processor.xslt" system
* property to the Xalan 2.x implementation. It also reads
* the "trax.wrapper.type" property to determine how we should
* perform transformations: eg, SAX2SAX, DOM2DOM, FILE2FILE, etc..</p>
* @param liaisonClassName [optional] if non-null & non-blank,
* classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception // Cover all exception cases
{
// Cleanup any prior objects
cleanup();
// Default the System property trax.processor.xslt
// to the FQCN of the xalan implementation, if needed
Properties props = System.getProperties();
// Get, with default, then put back to install default
String val = props.getProperty(TRAX_PROCESSOR_XSLT,
DEFAULT_PROCESSOR);
props.put(TRAX_PROCESSOR_XSLT, val);
// Get, with default, then put back to install default
val = props.getProperty(ORG_XML_SAX_DRIVER, DEFAULT_PARSER);
props.put(ORG_XML_SAX_DRIVER, val);
// Publish any changs.
// Note that this call may throw SecurityException in
// some cases, cf. if called from an applet
System.setProperties(props);
// Also get the 'type' of transformation we should perform
// with TRAX - using SAX, using files, DOMs, whatever
try
{
Integer i =
(Integer) typeMap.get(System.getProperty(TRAX_WRAPPER_TYPE,
DEFAULT_TRANSFORM));
transformType = i.intValue();
}
catch (Exception e)
{
// Just set the default; ignore the exception
transformType = DEFAULT_TYPE;
}
// Get a processor of 'xslt' stuff (i.e. Xalan)
processor = Processor.newInstance(XSLT);
p = (Object) processor;
// Return here; will be null if error or exception raised
return (p);
}
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor and possibly it's common options
*/
public String getDescription()
{
if (processor == null)
{
return ("ERROR: must call createNewProcessor first from: "
+ getDescription());
}
else
{
StringBuffer buf = new StringBuffer("TRaX");
buf.append(";");
buf.append("Java");
buf.append(";");
buf.append(
System.getProperties().getProperty(TRAX_PROCESSOR_XSLT)); // TODO - improve this
buf.append(";");
buf.append(System.getProperties().getProperty(TRAX_WRAPPER_TYPE)); // TODO - improve this
return buf.toString();
}
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* <p>This also respects the "trax.wrapper.type" System property to
* support different types of transforms.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception // Cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long xmlTime = 0;
long xslTime = 0;
// Create trax-specific sources
InputSource xsl = new InputSource(xslStylesheet); // TODO change to be URI
InputSource xml = new InputSource(xmlSource); // TODO change to be URI
// May throw IOException
// Note: use OutputStream derivative, not Writer derivative, so that
// the processor can properly control the output encoding!
FileOutputStream resultStream = new FileOutputStream(resultFile);
// Begin timing just the stylesheet creation
startTime = System.currentTimeMillis();
// Read and compile the stylesheet
Templates templates = processor.process(xsl);
xslTime = System.currentTimeMillis() - startTime;
switch (transformType)
{
// Each case does timing just on the transformation
case FILE_TO_FILE_TYPE : // OK SAXON
startTime = System.currentTimeMillis();
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
transformer.transform(xml, new Result(resultStream));
xmlTime = System.currentTimeMillis() - startTime;
break;
case DOM_TO_DOM_TYPE :
xmlTime = transformDOM2DOM(templates, xml, resultStream);
break;
case SAX_TO_SAX_TYPE :
xmlTime = transformSAX2SAX(templates, xml, resultStream);
break;
case SAX_TO_STREAM_TYPE :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
// break;
case DOM_TO_STREAM_TYPE :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
// break;
case STREAM_TO_DOM_TYPE :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
// break;
case AS_XML_FILTER_TYPE :
xmlTime = transformAsXMLFilter(templates, xml, resultStream);
break;
default :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
}
// Force output stream closed, just in case
resultStream.close();
// Return the sum of stylesheet create + transform time
return (xslTime + xmlTime);
}
/**
* Transform an xml document using SAX.
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws IOException
* @throws SAXException
* @throws TransformException
*/
private long transformSAX2SAX(
Templates templates, InputSource xml, OutputStream out)
throws TransformException, SAXException, IOException
{
long startTime = 0;
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
transformer.setContentHandler(serializer.asContentHandler()); // Use a TRaX serializer provided with Xalan
//x transformer.setProperty("http://xml.apache.org/xslt/sourcebase", xml.getSystemId());
//x XMLReader reader = XMLReaderFactory.createXMLReader();
XMLReader reader = new com.icl.saxon.aelfred.SAXDriver(); // Use SAXON's favorite parser
reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
true);
//x reader.setFeature("http://apache.org/xml/features/validation/dynamic", true);
ContentHandler chandler = transformer.getInputContentHandler();
reader.setContentHandler(chandler);
if (chandler instanceof org.xml.sax.ext.LexicalHandler)
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", chandler);
else
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", null);
// Only time the actual parsing (transforming)
startTime = System.currentTimeMillis();
reader.parse(xml); // Or should we call transformer.parse(), as the SAXON example has?
return (System.currentTimeMillis() - startTime);
}
/**
* Transform an xml document using .
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws IOException
* @throws SAXException
* @throws TransformException
*/
private long transformAsXMLFilter(
Templates templates, InputSource xml, OutputStream out)
throws TransformException, SAXException, IOException
{
long startTime = 0;
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
// Set the result handling to be a serialization to out
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
transformer.setContentHandler(serializer.asContentHandler());
// The transformer will use a SAX parser as it's reader.
// XMLReader reader = XMLReaderFactory.createXMLReader();
// transformer.setParent(reader);
// Instead of the standard (xerces) parser, use SAXON's favorite parser
transformer.setParent(new com.icl.saxon.aelfred.SAXDriver());
// Now, when you call transformer.parse, it will set itself as
// the content handler for the parser object (it's "parent"), and
// will then call the parse method on the parser.
// Only time the actual parsing (transforming)
startTime = System.currentTimeMillis();
transformer.parse(xml);
return (System.currentTimeMillis() - startTime);
}
/**
* Transform an xml document using DOMs.
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws Exception
*/
private long transformDOM2DOM(
Templates templates, InputSource xml, OutputStream out)
throws Exception // Just cover all cases, since we don't care which kind gets thrown
{
long startTime = 0;
if (!processor.getFeature("http://xml.org/trax/features/dom/input"))
{
throw new org.xml.sax.SAXNotSupportedException(
"DOM node processing not supported!");
}
DocumentBuilderFactory dfactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
/**
* NOTE: this part should really be done as a DOM, but it doesn't
* fit with our model - a big TODO for later on
* // Parse in the stylesheet
* Node xslDoc = docBuilder.parse(new InputSource(xslID));
*
* // Create the template from the DOM of the stylesheet
* Templates templates = processor.processFromNode(xslDoc);
*/
// Here, time the parsing of the XML doc, the transformation,
// and the serialization: this seems equivalent to what we
// time in the other methods
startTime = System.currentTimeMillis();
// Parse the XML data document the same way
Node xmlDoc = docBuilder.parse(xml);
// Saxon example uses a slightly different way:
// Use Xerces DOM
//sx DOMParser parser = new DOMParser();
//sx parser.parse(source(indir+"books.xml"));
//sx Document xmlDoc = parser.getDocument();
//sx Node outNode = new DocumentImpl();
// Run the transformation from the DOM nodes
org.w3c.dom.Document outNode = docBuilder.newDocument();
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
transformer.transformNode(xmlDoc, new Result(outNode));
// Use the serializers to output the result to disk
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
serializer.asDOMSerializer().serialize(outNode);
return (System.currentTimeMillis() - startTime);
}
/**
* Preprocess a stylesheet and set it into the processor, based on string inputs.
* @todo Does NOT respect the "trax.wrapper.type" System property yet.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create trax-specific sources
InputSource xsl = new InputSource(xslStylesheet);
// Begin timing the whole process
startTime = System.currentTimeMillis();
// Read and compile the stylesheet
savedStylesheet = processor.process(xsl);
endTime = System.currentTimeMillis();
stylesheetReady = true;
return (endTime - startTime);
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* @todo Does NOT respect the "trax.wrapper.type" System property yet.
* @param xmlSource name of source XML file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create trax-specific sources
InputSource xml = new InputSource(xmlSource);
// May throw IOException
FileOutputStream resultStream = new FileOutputStream(resultFile);
// Use the precompiled stylesheet
Transformer transformer = savedStylesheet.newTransformer();
applyParams(transformer, params);
// Begin timing the whole process
startTime = System.currentTimeMillis();
// HACK: this should work off of transformType as well!
transformer.transform(xml, new Result(resultStream));
endTime = System.currentTimeMillis();
// Force output stream closed, just in case
resultStream.close();
return (endTime - startTime);
}
/**
* Reset the state.
*/
public void reset()
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Does not appear to be applicable for TRaX?
stylesheetReady = false;
savedStylesheet = null;
params = null;
}
/**
* Set diagnostics output PrintWriter.
*
* NEEDSDOC @param pw
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Unimplemented; silently fail
// processor.setDiagnosticsOutput(pw);
}
/**
* Set the indent level of the processor.
*
* NEEDSDOC @param i
*/
public void setIndent(int i)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Unimplemented; silently fail
// TODO: implement for Xalan/LotusXSL specific setFeature()
// processor.getXMLProcessorLiaison().setIndent(i);
}
/**
* Set a String name=value param in the processor, if applicable.
*
* NEEDSDOC @param key
* NEEDSDOC @param expression
*/
public void setStylesheetParam(String key, String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
if (params == null)
params = new Hashtable();
// Just put the param in our hash; individual methods will
// make use of these later when needed
params.put(key, expression);
}
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @todo Needs Implementation: namespace is currently <b>ignored!</b>
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public void setStylesheetParam(String namespace, String key,
String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
if (params == null)
params = new Hashtable();
// Just put the param in our hash; individual methods will
// make use of these later when needed
params.put(key, expression);
}
/**
* Apply our set of parameters to a transformer.
*
* NEEDSDOC @param t
* NEEDSDOC @param h
*/
protected void applyParams(Transformer t, Hashtable h)
{
if (params == null)
return;
for (Enumeration enum = h.keys();
enum.hasMoreElements(); /* no increment portion */ )
{
Object key = enum.nextElement();
t.setParameter(key.toString(), null /* namespace TBD */,
h.get(key));
}
}
/** Worker method to cleanup any internal state. */
private void cleanup()
{
processor = null;
p = null;
stylesheetReady = false;
savedStylesheet = null;
params = null;
}
/**
* Create an InputSource that refers to a given File.
* @author Michael.Kay@icl.com
*
* NEEDSDOC @param filename
*
* NEEDSDOC ($objectName$) @return
*/
private static InputSource source(String filename)
{
File file = new File(filename);
String path = file.getAbsolutePath();
URL url = null;
try
{
url = new URL(path);
}
catch (MalformedURLException ex)
{
try
{
// This is a bunch of weird code that is required to
// make a valid URL on the Windows platform, due
// to inconsistencies in what getAbsolutePath returns.
String fs = System.getProperty("file.separator");
if (fs.length() == 1)
{
char sep = fs.charAt(0);
if (sep != '/')
path = path.replace(sep, '/');
if (path.charAt(0) != '/')
path = '/' + path;
}
path = "file://" + path;
url = new URL(path);
}
catch (MalformedURLException e)
{
return null;
}
}
return (new InputSource(url.toString()));
}
} // end of class SaxonWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/TraxWrapper.java
Index: TraxWrapper.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/>.
*/
/*
*
* TraxWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.io.PrintWriter; // currently only used in unimplemented setDiagnosticsOutput
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
// Needed SAX classes
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.XMLReader;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
// A generic TRaX-compliant wrapper
// NOTE: package name subject to change!
import org.apache.trax.Processor;
import org.apache.trax.Result;
import org.apache.trax.Templates;
import org.apache.trax.Transformer;
import org.apache.trax.TransformException;
import org.apache.serialize.SerializerFactory;
import org.apache.serialize.Serializer;
import org.apache.serialize.OutputFormat;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
/**
* Implementation of a ProcessorWrapper for a TrAX-compilant XSLT processor.
* <p>Currently defaults to the Xalan 2.x implementation, although
* it should respect the trax.processor.xslt system property.</p>
* @todo add better support for liaisons, or different processing
* models (DOM, SAX, from files, whatever), etc.
* @todo share constants between TraxWrapper, SaxonWrapper
* @todo document how we perform various types of transforms
* @author Shane Curcuru
* @version $Id: TraxWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public class TraxWrapper extends ProcessorWrapper
{
/** No-op Ctor for the generic TRAX interface wrapper. */
public TraxWrapper(){}
/** Reference to current processor - TRaX flavor - convenience method. */
protected org.apache.trax.Processor processor = null;
/**
* NEEDSDOC Method getTraxProcessor
*
*
* NEEDSDOC (getTraxProcessor) @return
*/
public org.apache.trax.Processor getTraxProcessor()
{
return (processor);
}
/** A preprocessed stylesheet that we're saving. */
private Templates savedStylesheet = null;
/** Whatever parameters the user has set. */
private Hashtable params = null;
/** Which type of transform we should perform. */
protected int transformType = DEFAULT_TYPE;
/** Constants for different types of transforms. */
public static final String FILE_TO_FILE = "file-to-file";
/** NEEDSDOC Field FILE_TO_FILE_TYPE */
public static final int FILE_TO_FILE_TYPE = 1;
/** NEEDSDOC Field DOM_TO_DOM */
public static final String DOM_TO_DOM = "dom-to-dom";
/** NEEDSDOC Field DOM_TO_DOM_TYPE */
public static final int DOM_TO_DOM_TYPE = 2;
/** NEEDSDOC Field SAX_TO_SAX */
public static final String SAX_TO_SAX = "sax-to-sax";
/** NEEDSDOC Field SAX_TO_SAX_TYPE */
public static final int SAX_TO_SAX_TYPE = 3;
/** NEEDSDOC Field SAX_TO_STREAM */
public static final String SAX_TO_STREAM = "sax-to-stream";
/** NEEDSDOC Field SAX_TO_STREAM_TYPE */
public static final int SAX_TO_STREAM_TYPE = 4;
/** NEEDSDOC Field DOM_TO_STREAM */
public static final String DOM_TO_STREAM = "dom-to-stream";
/** NEEDSDOC Field DOM_TO_STREAM_TYPE */
public static final int DOM_TO_STREAM_TYPE = 5;
/** NEEDSDOC Field STREAM_TO_DOM */
public static final String STREAM_TO_DOM = "stream-to-dom";
/** NEEDSDOC Field STREAM_TO_DOM_TYPE */
public static final int STREAM_TO_DOM_TYPE = 6;
/** NEEDSDOC Field AS_XML_FILTER */
public static final String AS_XML_FILTER = "as-xml-filter";
/** NEEDSDOC Field AS_XML_FILTER_TYPE */
public static final int AS_XML_FILTER_TYPE = 7;
/** NEEDSDOC Field DEFAULT_TRANSFORM */
public static final String DEFAULT_TRANSFORM = FILE_TO_FILE;
/** NEEDSDOC Field DEFAULT_TYPE */
public static final int DEFAULT_TYPE = FILE_TO_FILE_TYPE;
/**
* Mapping of transform types to integer constants.
*/
protected static Hashtable typeMap = null;
// Static class initializer for our typeMap
static
{
typeMap = new Hashtable();
typeMap.put(FILE_TO_FILE, new Integer(FILE_TO_FILE_TYPE));
typeMap.put(DOM_TO_DOM, new Integer(DOM_TO_DOM_TYPE));
typeMap.put(SAX_TO_SAX, new Integer(SAX_TO_SAX_TYPE));
typeMap.put(SAX_TO_STREAM, new Integer(SAX_TO_STREAM_TYPE));
typeMap.put(DOM_TO_STREAM, new Integer(DOM_TO_STREAM_TYPE));
typeMap.put(STREAM_TO_DOM, new Integer(STREAM_TO_DOM_TYPE));
typeMap.put(AS_XML_FILTER, new Integer(AS_XML_FILTER_TYPE));
}
;
/** Constants for system properties, etc.. */
public static final String TRAX_PROCESSOR = "trax.processor";
/** NEEDSDOC Field XSLT */
public static final String XSLT = "xslt";
/** NEEDSDOC Field TRAX_PROCESSOR_XSLT */
public static final String TRAX_PROCESSOR_XSLT = TRAX_PROCESSOR + "."
+ XSLT;
/** NEEDSDOC Field ORG_XML_SAX_DRIVER */
public static final String ORG_XML_SAX_DRIVER = "org.xml.sax.driver";
/** NEEDSDOC Field DEFAULT_PROCESSOR */
public static final String DEFAULT_PROCESSOR =
"org.apache.xalan.processor.StylesheetProcessor";
/** NEEDSDOC Field DEFAULT_PARSER */
public static final String DEFAULT_PARSER =
"org.apache.xerces.parsers.SAXParser";
/** NEEDSDOC Field TRAX_WRAPPER_TYPE */
public static final String TRAX_WRAPPER_TYPE = "trax.wrapper.type";
/**
* Construct a processor of the appropriate flavor, optionally specifying a liaison.
* <p>May throw exceptions related to the creating of a new processor.</p>
* <p>Note liaison support is not really implemented - a TODO item.</p>
* <p>This method defaults the "trax.processor.xslt" system
* property to the Xalan 2.x implementation. It also reads
* the "trax.wrapper.type" property to determine how we should
* perform transformations: eg, SAX2SAX, DOM2DOM, FILE2FILE, etc..</p>
* @param liaisonClassName [optional] if non-null & non-blank,
* classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception // Cover all exception cases
{
// Cleanup any prior objects
cleanup();
// Default the System property trax.processor.xslt
// to the FQCN of the xalan implementation, if needed
Properties props = System.getProperties();
// Get, with default, then put back to install default
String val = props.getProperty(TRAX_PROCESSOR_XSLT,
DEFAULT_PROCESSOR);
props.put(TRAX_PROCESSOR_XSLT, val);
// Get, with default, then put back to install default
val = props.getProperty(ORG_XML_SAX_DRIVER, DEFAULT_PARSER);
props.put(ORG_XML_SAX_DRIVER, val);
// Publish any changs.
// Note that this call may throw SecurityException in
// some cases, cf. if called from an applet
System.setProperties(props);
// Also get the 'type' of transformation we should perform
// with TRAX - using SAX, using files, DOMs, whatever
try
{
Integer i =
(Integer) typeMap.get(System.getProperty(TRAX_WRAPPER_TYPE,
DEFAULT_TRANSFORM));
transformType = i.intValue();
}
catch (Exception e)
{
// Just set the default; ignore the exception
transformType = DEFAULT_TYPE;
}
// Get a processor of 'xslt' stuff (i.e. Xalan)
processor = Processor.newInstance(XSLT);
p = (Object) processor;
// Return here; will be null if error or exception raised
return (p);
}
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor and possibly it's common options
*/
public String getDescription()
{
if (processor == null)
{
return ("ERROR: must call createNewProcessor first from: "
+ getDescription());
}
else
{
StringBuffer buf = new StringBuffer("TRaX");
buf.append(";");
buf.append("Java");
buf.append(";");
buf.append(
System.getProperties().getProperty(TRAX_PROCESSOR_XSLT)); // TODO - improve this
buf.append(";");
buf.append(System.getProperties().getProperty(TRAX_WRAPPER_TYPE)); // TODO - improve this
return buf.toString();
}
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* <p>This also respects the "trax.wrapper.type" System property to
* support different types of transforms.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception // Cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long xmlTime = 0;
long xslTime = 0;
// Create trax-specific sources
InputSource xsl = new InputSource(xslStylesheet);
InputSource xml = new InputSource(xmlSource);
// May throw IOException
// Note: use OutputStream derivative, not Writer derivative, so that
// the processor can properly control the output encoding!
FileOutputStream resultStream = new FileOutputStream(resultFile);
// Begin timing just the stylesheet creation
startTime = System.currentTimeMillis();
// Read and compile the stylesheet
Templates templates = processor.process(xsl);
xslTime = System.currentTimeMillis() - startTime;
switch (transformType)
{
// Each case does timing just on the transformation
case FILE_TO_FILE_TYPE :
startTime = System.currentTimeMillis();
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
transformer.transform(xml, new Result(resultStream));
xmlTime = System.currentTimeMillis() - startTime;
break;
case DOM_TO_DOM_TYPE :
xmlTime = transformDOM2DOM(templates, xml, resultStream);
break;
case SAX_TO_SAX_TYPE :
xmlTime = transformSAX2SAX(templates, xml, resultStream);
break;
case SAX_TO_STREAM_TYPE :
xmlTime = transformSAX2Stream(templates, xml, resultStream);
break;
case DOM_TO_STREAM_TYPE :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
// break;
case STREAM_TO_DOM_TYPE :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
// break;
case AS_XML_FILTER_TYPE :
xmlTime = transformAsXMLFilter(templates, xml, resultStream);
break;
default :
throw new java.lang.IllegalStateException("bad transformType("
+ transformType
+ ") for: "
+ TRAX_WRAPPER_TYPE);
}
// Force output stream closed, just in case
resultStream.close();
// Return the sum of stylesheet create + transform time
return (xslTime + xmlTime);
}
/**
* Transform an xml document using SAX.
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws IOException
* @throws SAXException
* @throws TransformException
*/
private long transformSAX2SAX(
Templates templates, InputSource xml, OutputStream out)
throws TransformException, SAXException, IOException
{
long startTime = 0;
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
transformer.setContentHandler(serializer.asContentHandler());
transformer.setProperty("http://xml.apache.org/xslt/sourcebase",
xml.getSystemId());
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
true);
reader.setFeature("http://apache.org/xml/features/validation/dynamic",
true);
ContentHandler chandler = transformer.getInputContentHandler();
reader.setContentHandler(chandler);
if (chandler instanceof org.xml.sax.ext.LexicalHandler)
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", chandler);
else
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", null);
// Only time the actual parsing (transforming)
startTime = System.currentTimeMillis();
reader.parse(xml);
return (System.currentTimeMillis() - startTime);
}
/**
* Transform an xml document using SAX to a stream (then write separately.
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws IOException
* @throws SAXException
* @throws TransformException
*/
private long transformSAX2Stream(
Templates templates, InputSource xml, OutputStream out)
throws TransformException, SAXException, IOException
{
long startTime = 0;
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // ???? How best to do this?
serializer.setOutputStream(baos);
transformer.setContentHandler(serializer.asContentHandler());
transformer.setProperty("http://xml.apache.org/xslt/sourcebase",
xml.getSystemId());
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
true);
reader.setFeature("http://apache.org/xml/features/validation/dynamic",
true);
ContentHandler chandler = transformer.getInputContentHandler();
reader.setContentHandler(chandler);
if (chandler instanceof org.xml.sax.ext.LexicalHandler)
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", chandler);
else
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", null);
// Only time the actual parsing (transforming)
startTime = System.currentTimeMillis();
reader.parse(xml);
long endTime = System.currentTimeMillis();
// Now actually write the output to disk
out.write(baos.toByteArray());
out.flush(); // Should we close() as well?
return (endTime - startTime);
}
/**
* Transform an xml document using .
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws IOException
* @throws SAXException
* @throws TransformException
*/
private long transformAsXMLFilter(
Templates templates, InputSource xml, OutputStream out)
throws TransformException, SAXException, IOException
{
long startTime = 0;
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
// Set the result handling to be a serialization to out
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
transformer.setContentHandler(serializer.asContentHandler());
// The transformer will use a SAX parser as it's reader.
XMLReader reader = XMLReaderFactory.createXMLReader();
transformer.setParent(reader);
// Now, when you call transformer.parse, it will set itself as
// the content handler for the parser object (it's "parent"), and
// will then call the parse method on the parser.
// Only time the actual parsing (transforming)
startTime = System.currentTimeMillis();
transformer.parse(xml);
return (System.currentTimeMillis() - startTime);
}
/**
* Transform an xml document using DOMs.
*
* NEEDSDOC @param templates
* NEEDSDOC @param xml
* NEEDSDOC @param out
* @return milliseconds process time took
*
* @throws Exception
*/
private long transformDOM2DOM(
Templates templates, InputSource xml, OutputStream out)
throws Exception // Just cover all cases, since we don't care which kind gets thrown
{
long startTime = 0;
if (!processor.getFeature("http://xml.org/trax/features/dom/input"))
{
throw new org.xml.sax.SAXNotSupportedException(
"DOM node processing not supported!");
}
DocumentBuilderFactory dfactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
/**
* NOTE: this part should really be done as a DOM, but it doesn't
* fit with our model - a big TODO for later on
* // Parse in the stylesheet
* Node xslDoc = docBuilder.parse(new InputSource(xslID));
*
* // Create the template from the DOM of the stylesheet
* Templates templates = processor.processFromNode(xslDoc);
*/
// Here, time the parsing of the XML doc, the transformation,
// and the serialization: this seems equivalent to what we
// time in the other methods
startTime = System.currentTimeMillis();
// Parse the XML data document the same way
Node xmlDoc = docBuilder.parse(xml);
// Run the transformation from the DOM nodes
org.w3c.dom.Document outNode = docBuilder.newDocument();
Transformer transformer = templates.newTransformer();
applyParams(transformer, params);
transformer.transformNode(xmlDoc, new Result(outNode));
// Use the serializers to output the result to disk
OutputFormat format = templates.getOutputFormat();
Serializer serializer = SerializerFactory.getSerializer(format);
serializer.setOutputStream(out);
serializer.asDOMSerializer().serialize(outNode);
return (System.currentTimeMillis() - startTime);
}
/**
* Preprocess a stylesheet and set it into the processor, based on string inputs.
* @todo Does NOT respect the "trax.wrapper.type" System property yet.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create trax-specific sources
InputSource xsl = new InputSource(xslStylesheet);
// Begin timing the whole process
startTime = System.currentTimeMillis();
// Read and compile the stylesheet
savedStylesheet = processor.process(xsl);
endTime = System.currentTimeMillis();
stylesheetReady = true;
return (endTime - startTime);
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* @todo Does NOT respect the "trax.wrapper.type" System property yet.
* @param xmlSource name of source XML file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create trax-specific sources
InputSource xml = new InputSource(xmlSource);
// May throw IOException
FileOutputStream resultStream = new FileOutputStream(resultFile);
// Use the precompiled stylesheet
Transformer transformer = savedStylesheet.newTransformer();
applyParams(transformer, params);
// Begin timing the whole process
startTime = System.currentTimeMillis();
// HACK: this should work off of transformType as well!
transformer.transform(xml, new Result(resultStream));
endTime = System.currentTimeMillis();
// Force output stream closed, just in case
resultStream.close();
return (endTime - startTime);
}
/**
* Reset the state.
*/
public void reset()
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Does not appear to be applicable for TRaX?
stylesheetReady = false;
savedStylesheet = null;
params = null;
}
/**
* Set diagnostics output PrintWriter.
*
* NEEDSDOC @param pw
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Unimplemented; silently fail
// processor.setDiagnosticsOutput(pw);
}
/**
* Set the indent level of the processor.
*
* NEEDSDOC @param i
*/
public void setIndent(int i)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Unimplemented; silently fail
// TODO: implement for Xalan/LotusXSL specific setFeature()
// processor.getXMLProcessorLiaison().setIndent(i);
}
/**
* Set a String name=value param in the processor, if applicable.
*
* NEEDSDOC @param key
* NEEDSDOC @param expression
*/
public void setStylesheetParam(String key, String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
if (params == null)
params = new Hashtable();
// Just put the param in our hash; individual methods will
// make use of these later when needed
params.put(key, expression);
}
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @todo Needs Implementation: namespace is currently <b>ignored!</b>
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public void setStylesheetParam(String namespace, String key,
String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
if (params == null)
params = new Hashtable();
// Just put the param in our hash; individual methods will
// make use of these later when needed
params.put(key, expression);
}
/**
* Apply our set of parameters to a transformer.
*
* NEEDSDOC @param t
* NEEDSDOC @param h
*/
protected void applyParams(Transformer t, Hashtable h)
{
if (params == null)
return;
for (Enumeration enum = h.keys();
enum.hasMoreElements(); /* no increment portion */ )
{
Object key = enum.nextElement();
t.setParameter(key.toString(), null /* namespace TBD */,
h.get(key));
}
}
/** Worker method to cleanup any internal state. */
private void cleanup()
{
processor = null;
p = null;
stylesheetReady = false;
savedStylesheet = null;
params = null;
}
} // end of class TraxWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/XTWrapper.class
<<Binary file>>
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/XTWrapper.java
Index: XTWrapper.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/>.
*/
/*
*
* XTWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.io.File;
import java.io.PrintWriter;
import java.net.URL;
// The XT (James Clark) implementation
import org.xml.sax.InputSource;
import org.xml.sax.Parser;
import com.jclark.xsl.sax.XMLProcessorEx;
import com.jclark.xsl.sax.XSLProcessorImpl;
import com.jclark.xsl.sax.OutputMethodHandlerImpl;
import com.jclark.xsl.sax.FileDestination;
/**
* Implementation of a ProcessorWrapper for XT.
* @author Shane Curcuru
* @version $Id: XTWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public class XTWrapper extends ProcessorWrapper
{
/** No-op Ctor for the Xalan-J 1.x wrapper. */
public XTWrapper(){}
/** Reference to current processor - XT flavor - convenience method. */
protected com.jclark.xsl.sax.XSLProcessorImpl processor = null;
/**
* NEEDSDOC Method getXTProcessor
*
*
* NEEDSDOC (getXTProcessor) @return
*/
public com.jclark.xsl.sax.XSLProcessorImpl getXTProcessor()
{
return (processor);
}
/**
* Construct a processor of the appropriate flavor, optionally specifying a liaison.
* <p>May throw exceptions related to the creating of a new processor.</p>
* <ul>XT supports ??? liaisons:
* <li>com.jclark.xml.sax.CommentDriver (default)</li>
* </ul>
* @param liaisonClassName [optional] if non-null & non-blank, classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception // Cover all exception cases
{
// Cleanup any prior objects
cleanup();
processor = new com.jclark.xsl.sax.XSLProcessorImpl();
if (liaisonClassName == null)
liaisonClassName = "com.jclark.xml.sax.CommentDriver"; // default
try
{
Object parserObj = Class.forName(liaisonClassName).newInstance();
if (parserObj instanceof XMLProcessorEx)
processor.setParser((XMLProcessorEx) parserObj);
else
processor.setParser((org.xml.sax.Parser) parserObj);
}
catch (Exception e)
{
System.err.println("createNewProcesor(xt) threw: "
+ e.toString());
e.printStackTrace();
processor = null;
}
p = (Object) processor;
// Return here; will be null if error or exception raised
return (p);
}
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor and possibly it's common options
*/
public String getDescription()
{
if (processor == null)
{
return ("ERROR: must call createNewProcessor first from: "
+ getDescription());
}
else
{
StringBuffer buf = new StringBuffer("XT");
buf.append(";");
buf.append("JAVA");
buf.append(";");
buf.append("unknown_version");
buf.append(";");
buf.append("unknown_liaison");
return buf.toString();
}
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception // Cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create XT-specific sources
OutputMethodHandlerImpl outHandler =
new OutputMethodHandlerImpl(processor);
outHandler.setDestination(new FileDestination(new File(resultFile)));
InputSource xmlIS = xtInputSourceFromString(xmlSource);
InputSource xslIS = xtInputSourceFromString(xslStylesheet);
// Begin timing the process: stylesheet, output, and process
startTime = System.currentTimeMillis();
processor.loadStylesheet(xslIS);
processor.setOutputMethodHandler(outHandler);
processor.parse(xmlIS);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Worker method for using XT to process.
*
* NEEDSDOC @param name
*
* NEEDSDOC ($objectName$) @return
*/
private InputSource xtInputSourceFromString(String name)
{
File file = new File(name);
String path = file.getAbsolutePath();
// Add absolute / to beginning if needed
if (path.charAt(0) != '/')
path = '/' + path;
try
{
java.net.URL temp = new URL("file", "", path);
return (new InputSource(temp.toString()));
}
catch (Exception e)
{
System.err.println("xtInputSourceFromString(xt) of: " + name
+ " threw: " + e.toString());
e.printStackTrace();
return (null);
}
}
/**
* Preprocess a stylesheet and set it into the processor, based on string inputs.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create XT-specific source
InputSource xslIS = xtInputSourceFromString(xslStylesheet);
// Begin timing loading the stylesheet
startTime = System.currentTimeMillis();
processor.loadStylesheet(xslIS); // side effect: also sets the stylesheet
endTime = System.currentTimeMillis();
stylesheetReady = true;
return (endTime - startTime);
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* @param xmlSource name of source XML file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Ensure we (apparently) have already processed a stylesheet
if (!stylesheetReady)
throw new java.lang.IllegalStateException(
"You must call preProcessStylesheet first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create XT-specific sources
OutputMethodHandlerImpl outHandler =
new OutputMethodHandlerImpl(processor);
outHandler.setDestination(new FileDestination(new File(resultFile)));
InputSource xmlIS = xtInputSourceFromString(xmlSource);
// Begin timing the process: stylesheet, output, and process
startTime = System.currentTimeMillis();
processor.setOutputMethodHandler(outHandler);
processor.parse(xmlIS);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Reset the state.
*/
public void reset()
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// processor.reset(); // FIXME: no applicable API?
stylesheetReady = false;
}
/**
* Set diagnostics output PrintWriter:unimplemented.
*
* NEEDSDOC @param pw
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
//processor.setDiagnosticsOutput(pw); // FIXME: no applicable API?
}
/**
* Set the indent level of the processor:unimplemented.
*
* NEEDSDOC @param i
*/
public void setIndent(int i)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// processor.getXMLProcessorLiaison().setIndent(i); // FIXME: needs to be implemented
}
/**
* Set a String name=value param in the processor, if applicable.
*
* NEEDSDOC @param key
* NEEDSDOC @param expression
*/
public void setStylesheetParam(String key, String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// NEEDSWORK: ensure XT is expecting the same kind of expression as other processors
processor.setParameter(key, (Object) expression);
}
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @todo Needs Implementation: namespace is currently <b>ignored!</b>
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public void setStylesheetParam(String namespace, String key,
String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// NEEDSWORK: ensure XT is expecting the same kind of expression as other processors
processor.setParameter(key, (Object) expression);
}
/** Worker method to cleanup any internal state. */
private void cleanup()
{
processor = null;
p = null;
stylesheetReady = false;
}
} // end of class XTWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/XalanWrapper.java
Index: XalanWrapper.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/>.
*/
/*
*
* XalanWrapper.java
*
*/
package org.apache.qetest.xslwrapper;
import java.util.Vector;
import java.io.PrintWriter;
// The Xalan (apache) implementation
import org.apache.xalan.xslt.XSLTProcessor;
import org.apache.xalan.xslt.XSLTProcessorFactory;
import org.apache.xalan.xslt.XSLTInputSource;
import org.apache.xalan.xslt.XSLTResultTarget;
import org.apache.xalan.xslt.XSLProcessorVersion;
/**
* Implementation of a ProcessorWrapper for Xalan 1.x builds.
* <p>See TraxWrapper for a Xalan 2.x wrapper solution.</p>
* @author Shane Curcuru
* @version $Id: XalanWrapper.java,v 1.1 2000/11/01 23:27:00 curcuru Exp $
*/
public class XalanWrapper extends ProcessorWrapper
{
/** No-op Ctor for the Xalan-J 1.x wrapper. */
public XalanWrapper(){}
/** Reference to current processor - Xalan flavor - convenience method. */
protected org.apache.xalan.xslt.XSLTProcessor processor = null;
/**
* NEEDSDOC Method getXalanProcessor
*
*
* NEEDSDOC (getXalanProcessor) @return
*/
public org.apache.xalan.xslt.XSLTProcessor getXalanProcessor()
{
return (processor);
}
/**
* Construct a processor of the appropriate flavor, optionally specifying a liaison.
* <p>May throw exceptions related to the creating of a new processor.</p>
* <ul>Xalan supports two liaisons:
* <li>org.apache.xalan.xpath.dtm.DTMLiaison</li>
* <li>org.apache.xalan.xpath.xdom.XercesLiaison</li>
* </ul>
* @param liaisonClassName [optional] if non-null & non-blank, classname of an XML liaison
* @return (Object)processor as a side effect; null if error
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public Object createNewProcessor(String liaisonClassName)
throws java.lang.Exception // Cover all exception cases
{
// Cleanup any prior objects
cleanup();
if (liaisonClassName != null)
processor =
org.apache.xalan.xslt.XSLTProcessorFactory.getProcessorUsingLiaisonName(
liaisonClassName);
else
processor =
org.apache.xalan.xslt.XSLTProcessorFactory.getProcessor();
p = (Object) processor;
// Return here; will be null if error or exception raised
return (p);
}
/**
* Get a description of the wrappered processor.
* @return info-string describing the processor and possibly it's common options
*/
public String getDescription()
{
if (processor == null)
{
return ("ERROR: must call createNewProcessor first from: "
+ getDescription());
}
else
{
StringBuffer buf = new StringBuffer(XSLProcessorVersion.PRODUCT);
buf.append(";");
buf.append(XSLProcessorVersion.LANGUAGE);
buf.append(";");
buf.append(XSLProcessorVersion.S_VERSION);
buf.append(";");
buf.append(processor.getXMLProcessorLiaison());
return buf.toString();
}
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* <p>May throw exceptions related to asking the processor to perform the process.</p>
* <p>Attempts to ask each processor to accomplish the task in the simplest
* and most obvious manner. Often copied from various processor's samples.</p>
* @param xmlSource name of source XML file
* @param xslStylesheet name of stylesheet XSL file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(
String xmlSource, String xslStylesheet, String resultFile)
throws java.lang.Exception // Cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
org.apache.xalan.xslt.XSLTInputSource xml =
new org.apache.xalan.xslt.XSLTInputSource(xmlSource);
org.apache.xalan.xslt.XSLTInputSource xsl =
new org.apache.xalan.xslt.XSLTInputSource(xslStylesheet);
org.apache.xalan.xslt.XSLTResultTarget result =
new org.apache.xalan.xslt.XSLTResultTarget(resultFile);
// Begin timing the whole process
startTime = System.currentTimeMillis();
processor.process(xml, xsl, result);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Preprocess a stylesheet and set it into the processor, based on string inputs.
* @param xslStylesheet name of stylesheet XSL file
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long preProcessStylesheet(String xslStylesheet)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
org.apache.xalan.xslt.StylesheetRoot sRoot;
org.apache.xalan.xslt.XSLTInputSource xsl =
new org.apache.xalan.xslt.XSLTInputSource(xslStylesheet);
// Begin timing loading the stylesheet
startTime = System.currentTimeMillis();
sRoot = processor.processStylesheet(xsl); // side effect: also sets the stylesheet
endTime = System.currentTimeMillis();
stylesheetReady = true;
return (endTime - startTime);
}
/**
* Process the xmlSource using the xslStylesheet to produce the resultFile.
* @param xmlSource name of source XML file
* @param resultFile name of output file, presumably XML
* @return milliseconds process time took or ProcessorWrapper.ERROR
* @exception Exception may be thrown by underlying operation
*
* @throws java.lang.Exception
*/
public long processToFile(String xmlSource, String resultFile)
throws java.lang.Exception // should cover all exception cases
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
// Ensure we (apparently) have already processed a stylesheet
if (!stylesheetReady)
throw new java.lang.IllegalStateException(
"You must call preProcessStylesheet first!");
// Declare variables ahead of time to minimize latency
long startTime = 0;
long endTime = 0;
// Create xalan-specific sources
org.apache.xalan.xslt.XSLTInputSource xml =
new org.apache.xalan.xslt.XSLTInputSource(xmlSource);
org.apache.xalan.xslt.XSLTResultTarget result =
new org.apache.xalan.xslt.XSLTResultTarget(resultFile);
// Begin timing the whole process
startTime = System.currentTimeMillis();
processor.process(xml, null, result);
endTime = System.currentTimeMillis();
return (endTime - startTime);
}
/**
* Reset the state.
* <p>This needs to be called after a process() call is invoked,
* if the processor is to be used again.</p>
*/
public void reset()
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.reset();
stylesheetReady = false;
}
/**
* Set diagnostics output PrintWriter.
*
* NEEDSDOC @param pw
*/
public void setDiagnosticsOutput(java.io.PrintWriter pw)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setDiagnosticsOutput(pw);
}
/**
* Set the indent level of the processor.
*
* NEEDSDOC @param i
*/
public void setIndent(int i)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.getXMLProcessorLiaison().setIndent(i);
}
/**
* Set a String name=value param in the processor, if applicable.
*
* NEEDSDOC @param key
* NEEDSDOC @param expression
*/
public void setStylesheetParam(String key, String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setStylesheetParam(key, expression);
}
/**
* Set a String namespace:name=value param in the processor, if applicable.
* @todo Needs Implementation: namespace is currently <b>ignored!</b>
* @param namespace of the param
* @param key name of the param
* @param expression value of the param
*/
public void setStylesheetParam(String namespace, String key,
String expression)
{
// Ensure we (apparently) have some processor
if (processor == null)
throw new java.lang.IllegalStateException(
"You must call createNewProcessor first!");
processor.setStylesheetParam(key, expression);
}
/** Worker method to cleanup any internal state. */
private void cleanup()
{
processor = null;
p = null;
stylesheetReady = false;
}
} // end of class XalanWrapper
1.1 xml-xalan/test/java/src/org/apache/qetest/xslwrapper/package.html
Index: package.html
===================================================================
<html>
<title>XSL-TEST xslwrapper package.</title>
<body>
<p>This package provides an abstraction layer for XSLT processors through {@link ProcessorWrapper}.</p>
<dl>
<dt><b>Author: </b></dt><dd><a href="mailto:shane_curcuru@lotus.com">Shane_Curcuru@lotus.com</a></dd>
<dt><b>Program(s) Under Test: </b></dt>
<dd><a href="http://xml.apache.org/xalan-j" target="_top">Xalan-J 2.x XSLT Processor</a></dd>
<dd><a href="http://xml.apache.org/xalan" target="_top">Xalan-J 1.x XSLT Processor</a></dd>
</dl>
<p>This package also provides a number of implementations
for varying XSLT processors, including Xalan-J 1.x,
Xalan-J 2.x using the TRAX interface, and others.<p>
<p>This allows many test classes to eliminate dependencies
on a specific processor and be able to plug-and-play
different processors to compare test results.<p>
<p>See ProcessorWrapper.properties for info on how a -flavor
can get mapped into a specific implementation and 'type'
of a ProcessorWrapper.</p>
</body>
</html>