blob: 6ef27fbd1e5de5cd9a15de4b305b0e8bd8f61c98 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id$
*/
package org.apache.qetest.xslwrapper;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.apache.xalan.xsltc.cmdline.Compile;
import org.apache.xalan.xsltc.cmdline.Transform;
/**
* Implementation of TransformWrapper that uses the command line
* wrappers of XSLTC - interim use only.
*
* <b>Important!</b> This wrapper is for temporary use only: we
* should really focus on getting XSLTC to use JAXP 1.1 as it's
* interface, and then (as needed) write another custom wrapper
* that calls XSLTC API's directly.
*
* @author Shane Curcuru
* @version $Id$
*/
public class XsltcMainWrapper extends TransformWrapperHelper
{
private static final char CLEAN_CHAR = '_';
protected static final String XSLTC_COMPILER_CLASS = "org.apache.xalan.xsltc.cmdline.Compile";
protected static final String XSLTC_RUNTIME_CLASS = "org.apache.xalan.xsltc.cmdline.Transform";
private static final char FILE_SEPARATOR = System.getProperty("file.separator").charAt(0);
/**
* Cached copy of newProcessor() Hashtable.
*/
protected Hashtable newProcessorOpts = null;
/**
* Get a general description of this wrapper itself.
*
* @return Uses XSLTC command line to perform transforms
*/
public String getDescription()
{
return "Uses XSLTC command line to perform transforms";
}
/**
* Get a specific description of the wrappered processor.
*
* @return specific description of the underlying processor or
* transformer implementation: this should include both the
* general product name, as well as specific version info. If
* possible, should be implemented without actively creating
* an underlying processor.
*/
public Properties getProcessorInfo()
{
Properties p = TraxWrapperUtils.getTraxInfo();
p.put("traxwrapper.method", "streams");
p.put("traxwrapper.desc", getDescription());
return p;
}
/**
* Actually create/initialize an underlying processor or factory.
*
* Effectively a no-op; returns null. Just forces a reset().
*
* @param options Hashtable of options, unused.
*
* @return (Object)getProcessor() as a side-effect, this will
* be null if there was any problem creating the processor OR
* if the underlying implementation doesn't use this
*
* @throws Exception covers any underlying exceptions thrown
* by the actual implementation
*/
public Object newProcessor(Hashtable options) throws Exception
{
newProcessorOpts = options;
//@todo do we need to do any other cleanup?
reset(false);
return null;
}
/**
* Transform supplied xmlName file with the stylesheet in the
* xslName file into a resultName file.
*
* Names are assumed to be local path\filename references, and
* will be converted to URLs as needed for any underlying
* processor implementation.
*
* @param xmlName local path\filename of XML file to transform
* @param xslName local path\filename of XSL stylesheet to use
* @param resultName local path\filename to put result in
/* TWA - temp hack; use results dir to get path for to use for a dir to put
the translets
*/
/*
* @return array of longs denoting timing of only these parts of
* our operation: IDX_OVERALL, IDX_XSLBUILD, IDX_TRANSFORM
*
* @throws Exception any underlying exceptions from the
* wrappered processor are simply allowed to propagate; throws
* a RuntimeException if any other problems prevent us from
* actually completing the operation
*/
public long[] transform(String xmlName, String xslName, String resultName)
throws Exception
{
long startTime = 0;
long xslBuild = 0;
long transform = 0;
// java org.apache.xalan.xlstc.cmdline.Compile play1.xsl
// java org.apache.xalan.xlstc.cmdline.Transform play.xml play1 >stdout
// Timed: compile stylesheet class from XSL file
// String[] args1 = new String[2];
/* TWA - commented out the following for short-term
Problem when local path/file is being used, somewhere a file://// prefix is
being appended to the filename and xsltc can't find the file even with the -u
So I strip off the protocol prefix and pass the local path/file
args1[0] = "-u"; // Using URIs
args1[1] = xslName;
*/
/* TWA - temporay hack to construct and pass a directory for translets */
int last = resultName.lastIndexOf(FILE_SEPARATOR);
String tdir = resultName.substring(0, last);
int next = tdir.lastIndexOf(FILE_SEPARATOR);
String transletsdirName = tdir.substring(0, next);
String[] args1 = new String[3];
args1[0] = "-d";
args1[1] = transletsdirName;
args1[2] = xslName;
int idx = xslName.indexOf("file:////");
if (idx != -1){
xslName = new String(xslName.substring(8));
args1[2] = xslName;
}
startTime = System.currentTimeMillis();
/// Transformer transformer = factory.newTransformer(new StreamSource(xslName));
Compile.main(args1);
xslBuild = System.currentTimeMillis() - startTime;
// Verify output file was created
// WARNING: assumption of / here, which means we assume URI not local path - needs revisiting
int nameStart = xslName.lastIndexOf(FILE_SEPARATOR) + 1;
String baseName = xslName.substring(nameStart);
int extStart = baseName.lastIndexOf('.');
if (extStart > 0) {
baseName = baseName.substring(0, extStart);
}
// Replace illegal class name chars with underscores.
StringBuffer sb = new StringBuffer(baseName.length());
char charI = baseName.charAt(0);
sb.append(Character.isJavaLetter(charI) ? charI :CLEAN_CHAR);
for (int i = 1; i < baseName.length(); i++) {
charI = baseName.charAt(i);
sb.append(Character.isJavaLetterOrDigit(charI) ? charI :CLEAN_CHAR);
}
baseName = sb.toString();
// Untimed: Apply any parameters needed
// applyParameters(transformer);
// Timed: read/build xml, transform, and write results
/* TWA - I don't see how this could have worked, there is no -s option in DefaultRun
so passing it in the args2 caused usage messages to be output.
Also, we shouldn't use the -u option unless we are really using URLs,
I'm just trying to get it to work with local path/files. With or without the
-u option, the files were getting a file://// prefix with caused them to be not found
String[] args2 = new String[3];
args2[0] = "-s"; // Don't allow System.exit
args2[1] = "-u"; // Using URIs
args2[2] = xmlName;
args2[3] = baseName; // Just basename of the .class file, without the .class
// Note that . must be on CLASSPATH to work!
*/
String[] tempParam = makeParamArray();
String[] args2 = new String[2 + tempParam.length];
args2[0] = xmlName;
int idx2 = xmlName.indexOf("file:////");
if (idx2 != -1){
args2[0] = new String(xmlName.substring(8));
}
args2[1] = baseName;
System.arraycopy(tempParam, 0, args2, 2, tempParam.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream newSystemOut = new PrintStream(baos);
PrintStream saveSystemOut = System.out;
startTime = System.currentTimeMillis();
// transformer.transform(new StreamSource(xmlName), new StreamResult(resultName));
try
{
// Capture System.out into our byte array
System.setOut(new PrintStream(baos));
Transform.main(args2);
}
finally
{
// Be sure to restore System stuff!
System.setOut(saveSystemOut);
}
// Writing data should really go in separate timing loop
FileOutputStream fos = new FileOutputStream(resultName);
fos.write(baos.toByteArray());
fos.close();
transform = System.currentTimeMillis() - startTime;
File compiledXslClass = new File(baseName + ".class");
//@todo WARNING! We REALLY need to clean up the name*.class files when we're done!!! -sc
// TWA - we should probably use the -d option to put them in a desired directory first
// I commented out the delete, to see if the translets were getting compiled
// if (compiledXslClass.exists())
// compiledXslClass.delete();
long[] times = getTimeArray();
times[IDX_OVERALL] = xslBuild + transform;
times[IDX_XSLBUILD] = xslBuild;
times[IDX_TRANSFORM] = transform;
return times;
}
private String[] makeParamArray() {
if (m_params == null) {
return new String[0];
}
String[] params = new String[m_params.size()];
Iterator iter = m_params.entrySet().iterator();
int i = 0;
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
params[i++] = entry.getKey() + "=" + entry.getValue();
}
return params;
}
/**
* Pre-build/pre-compile a stylesheet.
*
* Although the actual mechanics are implementation-dependent,
* most processors have some method of pre-setting up the data
* needed by the stylesheet itself for later use in transforms.
* In TrAX/javax.xml.transform, this equates to creating a
* Templates object.
*
* Sets isStylesheetReady() to true if it succeeds. Users can
* then call transformWithStylesheet(xmlName, resultName) to
* actually perform a transformation with this pre-built
* stylesheet.
*
* @param xslName local path\filename of XSL stylesheet to use
*
* @return array of longs denoting timing of only these parts of
* our operation: IDX_OVERALL, IDX_XSLBUILD
*
* @throws Exception any underlying exceptions from the
* wrappered processor are simply allowed to propagate; throws
* a RuntimeException if any other problems prevent us from
* actually completing the operation
*
* @see #transformWithStylesheet(String xmlName, String resultName)
*/
public long[] buildStylesheet(String xslName) throws Exception
{
throw new RuntimeException("buildStylesheet not implemented yet!");
}
/**
* Transform supplied xmlName file with a pre-built/pre-compiled
* stylesheet into a resultName file.
*
* User must have called buildStylesheet(xslName) beforehand,
* obviously.
* Names are assumed to be local path\filename references, and
* will be converted to URLs as needed.
*
* @param xmlName local path\filename of XML file to transform
* @param resultName local path\filename to put result in
*
* @return array of longs denoting timing of only these parts of
* our operation: IDX_OVERALL, IDX_XSLBUILD, IDX_TRANSFORM
*
* @throws Exception any underlying exceptions from the
* wrappered processor are simply allowed to propagate; throws
* a RuntimeException if any other problems prevent us from
* actually completing the operation; throws an
* IllegalStateException if isStylesheetReady() == false.
*
* @see #buildStylesheet(String xslName)
*/
public long[] transformWithStylesheet(String xmlName, String resultName)
throws Exception
{
if (!isStylesheetReady())
throw new IllegalStateException("transformWithStylesheet() when isStylesheetReady() == false");
throw new RuntimeException("transformWithStylesheet not implemented yet!");
}
/**
* Transform supplied xmlName file with a stylesheet found in an
* xml-stylesheet PI into a resultName file.
*
* Names are assumed to be local path\filename references, and
* will be converted to URLs as needed. Implementations will
* use whatever facilities exist in their wrappered processor
* to fetch and build the stylesheet to use for the transform.
*
* @param xmlName local path\filename of XML file to transform
* @param resultName local path\filename to put result in
*
* @return array of longs denoting timing of only these parts of
* our operation: IDX_OVERALL, IDX_XSLREAD (time to find XSL
* reference from the xml-stylesheet PI), IDX_XSLBUILD, (time
* to then build the Transformer therefrom), IDX_TRANSFORM
*
* @throws Exception any underlying exceptions from the
* wrappered processor are simply allowed to propagate; throws
* a RuntimeException if any other problems prevent us from
* actually completing the operation
*/
public long[] transformEmbedded(String xmlName, String resultName)
throws Exception
{
throw new RuntimeException("transformEmbedded not implemented yet!");
}
/**
* Reset our parameters and wrapper state, and optionally
* force creation of a new underlying processor implementation.
*
* This always clears our built stylesheet and any parameters
* that have been set. If newProcessor is true, also forces a
* re-creation of our underlying processor as if by calling
* newProcessor().
*
* @param newProcessor if we should reset our underlying
* processor implementation as well
*/
public void reset(boolean newProcessor)
{
super.reset(newProcessor); // clears indent and parameters
m_stylesheetReady = false;
// builtTemplates = null;
if (newProcessor)
{
try
{
newProcessor(newProcessorOpts);
}
catch (Exception e)
{
//@todo Hmm: what should we do here?
}
}
}
/**
* Apply a single parameter to a Transformer.
*
* WARNING: Not implemented! 27-Apr-01
*
* @param passThru to be passed to each applyParameter() method
* call - for TrAX, you might pass a Transformer object.
* @param namespace for the parameter, may be null
* @param name for the parameter, should not be null
* @param value for the parameter, may be null
*/
protected void applyParameter(Object passThru, String namespace,
String name, Object value)
{
/* WARNING: Not implemented! 27-Apr-01 */
}
}