1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id$ 20 */ 21 package org.apache.qetest.xslwrapper; 22 import java.util.Hashtable; 23 import java.util.Properties; 24 import java.util.StringTokenizer; 25 import java.util.Vector; 26 27 import org.apache.qetest.QetestUtils; 28 29 /** 30 * Implementation of TransformWrapper that calls Xalan's default 31 * command line class Process.main. 32 * 33 * This is similar to the common usage: 34 * java org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ... 35 * 36 * See OPT_PREFIX for how to pass miscellaneous cmdline args. 37 * 38 * //@todo support precompiled/serialized stylesheets 39 * 40 * @author Shane_Curcuru@us.ibm.com 41 * @version $Id$ 42 */ 43 public class XalanProcessWrapper extends TransformWrapperHelper 44 { 45 46 /** 47 * Marker for cmdline items to add to optionArgs. 48 */ 49 public static final String OPT_PREFIX = TransformWrapper.SET_PROCESSOR_ATTRIBUTES + "cmdline"; 50 51 52 /** 53 * Array of additional or optional args for Process.main() calls. 54 */ 55 protected String[] optionArgs = new String[0]; 56 57 58 /** 59 * Cached copy of newProcessor() Hashtable. 60 */ 61 protected Hashtable newProcessorOpts = null; 62 63 64 /** 65 * Get a general description of this wrapper itself. 66 * 67 * @return Calls org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ... 68 */ getDescription()69 public String getDescription() 70 { 71 return "Calls org.apache.xalan.xslt.Process -in foo.xml -xsl foo.xsl ..."; 72 } 73 74 75 /** 76 * Get a specific description of the wrappered processor. 77 * 78 * @return specific description of the underlying processor or 79 * transformer implementation: this should include both the 80 * general product name, as well as specific version info. If 81 * possible, should be implemented without actively creating 82 * an underlying processor. 83 */ getProcessorInfo()84 public Properties getProcessorInfo() 85 { 86 Properties p = TraxWrapperUtils.getTraxInfo(); 87 p.put("traxwrapper.method", "xalanProcess"); 88 p.put("traxwrapper.desc", getDescription()); 89 return p; 90 } 91 92 93 /** 94 * Actually create/initialize an underlying processor or factory. 95 * 96 * No-op, since we always construct a new Process instance 97 * for every transformation. 98 * 99 * @param options Hashtable of options, unused. 100 * 101 * @return null, we don't use this 102 * 103 * @throws Exception covers any underlying exceptions thrown 104 * by the actual implementation 105 */ newProcessor(Hashtable options)106 public Object newProcessor(Hashtable options) throws Exception 107 { 108 newProcessorOpts = options; 109 110 // semi-HACK: set any additional cmdline options from user 111 String extraOpts = null; 112 try 113 { 114 // Attempt to use as a Properties block.. 115 extraOpts = ((Properties)options).getProperty(OPT_PREFIX); 116 // But, if null, then try getting as hash anyway 117 if (null == extraOpts) 118 { 119 extraOpts = (String)options.get(OPT_PREFIX); 120 } 121 } 122 catch (ClassCastException cce) 123 { 124 // .. but fallback to get as Hashtable instead 125 extraOpts = (String)options.get(OPT_PREFIX); 126 } 127 128 if ((null != extraOpts) && (extraOpts.length() > 0)) 129 { 130 Vector v = new Vector(); 131 StringTokenizer st = new StringTokenizer(extraOpts, " "); 132 while (st.hasMoreTokens()) 133 { 134 v.addElement(st.nextToken()); 135 } 136 optionArgs = new String[v.size()]; 137 v.copyInto(optionArgs); 138 } 139 //@todo do we need to do any other cleanup? 140 reset(false); 141 return null; 142 } 143 144 145 /** 146 * Transform supplied xmlName file with the stylesheet in the 147 * xslName file into a resultName file. 148 * 149 * Names are assumed to be local path\filename references, and 150 * will be converted to URLs as needed for any underlying 151 * processor implementation. 152 * 153 * //@todo attempt to capture any System.out/err output 154 * from this command line class for logging 155 * 156 * @param xmlName local path\filename of XML file to transform 157 * @param xslName local path\filename of XSL stylesheet to use 158 * @param resultName local path\filename to put result in 159 * 160 * @return array of longs denoting timing of only these parts of 161 * our operation: IDX_OVERALL 162 * 163 * @throws Exception any underlying exceptions from the 164 * wrappered processor are simply allowed to propagate; throws 165 * a RuntimeException if any other problems prevent us from 166 * actually completing the operation 167 */ transform(String xmlName, String xslName, String resultName)168 public long[] transform(String xmlName, String xslName, String resultName) 169 throws Exception 170 { 171 long startTime = 0; 172 long overall = 0; 173 174 // Untimed: Apply any parameters needed 175 applyParameters(null); 176 177 // Untimed: Construct command line array 178 final int NUM_FARGS = 6; // Need 6 extra slots for 179 // -in XML -xsl XSL -out OUT 180 String args[] = new String[optionArgs.length + NUM_FARGS]; 181 182 args[0] = "-in"; 183 args[1] = QetestUtils.filenameToURL(xmlName); 184 args[2] = "-xsl"; 185 args[3] = QetestUtils.filenameToURL(xslName); 186 args[4] = "-out"; 187 args[5] = resultName; 188 System.arraycopy(optionArgs, 0, args, NUM_FARGS, optionArgs.length); 189 190 // Timed: entire operation 191 //@todo attempt to capture any System.out/err output 192 // from this command line class for logging 193 startTime = System.currentTimeMillis(); 194 org.apache.xalan.xslt.Process.main(args); 195 overall = System.currentTimeMillis() - startTime; 196 197 long[] times = getTimeArray(); 198 times[IDX_OVERALL] = overall; 199 return times; 200 } 201 202 203 /** 204 * Pre-build/pre-compile a stylesheet. 205 * 206 * Although the actual mechanics are implementation-dependent, 207 * most processors have some method of pre-setting up the data 208 * needed by the stylesheet itself for later use in transforms. 209 * In TrAX/javax.xml.transform, this equates to creating a 210 * Templates object. 211 * 212 * Sets isStylesheetReady() to true if it succeeds. Users can 213 * then call transformWithStylesheet(xmlName, resultName) to 214 * actually perform a transformation with this pre-built 215 * stylesheet. 216 * 217 * @param xslName local path\filename of XSL stylesheet to use 218 * 219 * @return array of longs denoting timing of only these parts of 220 * our operation: IDX_OVERALL, IDX_XSLBUILD 221 * 222 * @throws Exception any underlying exceptions from the 223 * wrappered processor are simply allowed to propagate; throws 224 * a RuntimeException if any other problems prevent us from 225 * actually completing the operation 226 * 227 * @see #transformWithStylesheet(String xmlName, String resultName) 228 */ buildStylesheet(String xslName)229 public long[] buildStylesheet(String xslName) throws Exception 230 { 231 throw new IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); 232 } 233 234 235 /** 236 * Transform supplied xmlName file with a pre-built/pre-compiled 237 * stylesheet into a resultName file. 238 * 239 * User must have called buildStylesheet(xslName) beforehand, 240 * obviously. 241 * Names are assumed to be local path\filename references, and 242 * will be converted to URLs as needed. 243 * 244 * @param xmlName local path\filename of XML file to transform 245 * @param resultName local path\filename to put result in 246 * 247 * @return array of longs denoting timing of only these parts of 248 * our operation: IDX_OVERALL, IDX_XSLBUILD, IDX_TRANSFORM 249 * 250 * @throws Exception any underlying exceptions from the 251 * wrappered processor are simply allowed to propagate; throws 252 * a RuntimeException if any other problems prevent us from 253 * actually completing the operation; throws an 254 * IllegalStateException if isStylesheetReady() == false. 255 * 256 * @see #buildStylesheet(String xslName) 257 */ transformWithStylesheet(String xmlName, String resultName)258 public long[] transformWithStylesheet(String xmlName, String resultName) 259 throws Exception 260 { 261 throw new IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); 262 } 263 264 265 /** 266 * Transform supplied xmlName file with a stylesheet found in an 267 * xml-stylesheet PI into a resultName file. 268 * 269 * Names are assumed to be local path\filename references, and 270 * will be converted to URLs as needed. Implementations will 271 * use whatever facilities exist in their wrappered processor 272 * to fetch and build the stylesheet to use for the transform. 273 * 274 * @param xmlName local path\filename of XML file to transform 275 * @param resultName local path\filename to put result in 276 * 277 * @return array of longs denoting timing of only these parts of 278 * our operation: IDX_OVERALL, IDX_XSLREAD (time to find XSL 279 * reference from the xml-stylesheet PI), IDX_XSLBUILD, (time 280 * to then build the Transformer therefrom), IDX_TRANSFORM 281 * 282 * @throws Exception any underlying exceptions from the 283 * wrappered processor are simply allowed to propagate; throws 284 * a RuntimeException if any other problems prevent us from 285 * actually completing the operation 286 */ transformEmbedded(String xmlName, String resultName)287 public long[] transformEmbedded(String xmlName, String resultName) 288 throws Exception 289 { 290 throw new IllegalStateException("XalanProcessWrapper.transformWithStylesheet not implemented!"); 291 } 292 293 294 /** 295 * Reset our parameters and wrapper state, and optionally 296 * force creation of a new underlying processor implementation. 297 * 298 * This always clears our built stylesheet and any parameters 299 * that have been set. If newProcessor is true, also forces a 300 * re-creation of our underlying processor as if by calling 301 * newProcessor(). 302 * 303 * @param newProcessor if we should reset our underlying 304 * processor implementation as well 305 */ reset(boolean newProcessor)306 public void reset(boolean newProcessor) 307 { 308 super.reset(newProcessor); // clears indent and parameters 309 m_stylesheetReady = false; 310 } 311 312 313 /** 314 * Apply a single parameter to a Transformer. 315 * 316 * No-op, we don't yet support parameters. 317 * 318 * @param passThru to be passed to each applyParameter() method 319 * @param namespace for the parameter, may be null 320 * @param name for the parameter, should not be null 321 * @param value for the parameter, may be null 322 */ applyParameter(Object passThru, String namespace, String name, Object value)323 protected void applyParameter(Object passThru, String namespace, 324 String name, Object value) 325 { 326 return; 327 } 328 329 330 } 331