/* * 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.util.Hashtable; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import org.apache.qetest.QetestUtils; /** * Implementation of TransformWrapper that calls Xalan's default * command line class Process.main. * * This is similar to the common usage: * java org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ... * * See OPT_PREFIX for how to pass miscellaneous cmdline args. * * //@todo support precompiled/serialized stylesheets * * @author Shane_Curcuru@us.ibm.com * @version $Id$ */ public class XalanProcessWrapper extends TransformWrapperHelper { /** * Marker for cmdline items to add to optionArgs. */ public static final String OPT_PREFIX = TransformWrapper.SET_PROCESSOR_ATTRIBUTES + "cmdline"; /** * Array of additional or optional args for Process.main() calls. */ protected String[] optionArgs = new String[0]; /** * Cached copy of newProcessor() Hashtable. */ protected Hashtable newProcessorOpts = null; /** * Get a general description of this wrapper itself. * * @return Calls org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ... */ public String getDescription() { return "Calls org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ..."; } /** * 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", "xalanProcess"); p.put("traxwrapper.desc", getDescription()); return p; } /** * Actually create/initialize an underlying processor or factory. * * No-op, since we always construct a new Process instance * for every transformation. * * @param options Hashtable of options, unused. * * @return null, we don't use this * * @throws Exception covers any underlying exceptions thrown * by the actual implementation */ public Object newProcessor(Hashtable options) throws Exception { newProcessorOpts = options; // semi-HACK: set any additional cmdline options from user String extraOpts = null; try { // Attempt to use as a Properties block.. extraOpts = ((Properties)options).getProperty(OPT_PREFIX); // But, if null, then try getting as hash anyway if (null == extraOpts) { extraOpts = (String)options.get(OPT_PREFIX); } } catch (ClassCastException cce) { // .. but fallback to get as Hashtable instead extraOpts = (String)options.get(OPT_PREFIX); } if ((null != extraOpts) && (extraOpts.length() > 0)) { Vector v = new Vector(); StringTokenizer st = new StringTokenizer(extraOpts, " "); while (st.hasMoreTokens()) { v.addElement(st.nextToken()); } optionArgs = new String[v.size()]; v.copyInto(optionArgs); } //@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. * * //@todo attempt to capture any System.out/err output * from this command line class for logging * * @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 * * @return array of longs denoting timing of only these parts of * our operation: IDX_OVERALL * * @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 overall = 0; // Untimed: Apply any parameters needed applyParameters(null); // Untimed: Construct command line array final int NUM_FARGS = 6; // Need 6 extra slots for // -in XML -xsl XSL -out OUT String args[] = new String[optionArgs.length + NUM_FARGS]; args[0] = "-in"; args[1] = QetestUtils.filenameToURL(xmlName); args[2] = "-xsl"; args[3] = QetestUtils.filenameToURL(xslName); args[4] = "-out"; args[5] = resultName; System.arraycopy(optionArgs, 0, args, NUM_FARGS, optionArgs.length); // Timed: entire operation //@todo attempt to capture any System.out/err output // from this command line class for logging startTime = System.currentTimeMillis(); org.apache.xalan.xslt.Process.main(args); overall = System.currentTimeMillis() - startTime; long[] times = getTimeArray(); times[IDX_OVERALL] = overall; return times; } /** * 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 IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); } /** * 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 { throw new IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); } /** * 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 IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); } /** * 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; } /** * Apply a single parameter to a Transformer. * * No-op, we don't yet support parameters. * * @param passThru to be passed to each applyParameter() method * @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) { return; } }