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.io.ByteArrayOutputStream; 23 import java.io.File; 24 import java.io.FileOutputStream; 25 import java.io.PrintStream; 26 import java.util.Hashtable; 27 import java.util.Iterator; 28 import java.util.Map; 29 import java.util.Properties; 30 31 import org.apache.xalan.xsltc.cmdline.Compile; 32 import org.apache.xalan.xsltc.cmdline.Transform; 33 34 /** 35 * Implementation of TransformWrapper that uses the command line 36 * wrappers of XSLTC - interim use only. 37 * 38 * <b>Important!</b> This wrapper is for temporary use only: we 39 * should really focus on getting XSLTC to use JAXP 1.1 as it's 40 * interface, and then (as needed) write another custom wrapper 41 * that calls XSLTC API's directly. 42 * 43 * @author Shane Curcuru 44 * @version $Id$ 45 */ 46 public class XsltcMainWrapper extends TransformWrapperHelper 47 { 48 49 private static final char CLEAN_CHAR = '_'; 50 protected static final String XSLTC_COMPILER_CLASS = "org.apache.xalan.xsltc.cmdline.Compile"; 51 protected static final String XSLTC_RUNTIME_CLASS = "org.apache.xalan.xsltc.cmdline.Transform"; 52 53 private static final char FILE_SEPARATOR = System.getProperty("file.separator").charAt(0); 54 55 /** 56 * Cached copy of newProcessor() Hashtable. 57 */ 58 protected Hashtable newProcessorOpts = null; 59 60 /** 61 * Get a general description of this wrapper itself. 62 * 63 * @return Uses XSLTC command line to perform transforms 64 */ getDescription()65 public String getDescription() 66 { 67 return "Uses XSLTC command line to perform transforms"; 68 } 69 70 71 /** 72 * Get a specific description of the wrappered processor. 73 * 74 * @return specific description of the underlying processor or 75 * transformer implementation: this should include both the 76 * general product name, as well as specific version info. If 77 * possible, should be implemented without actively creating 78 * an underlying processor. 79 */ getProcessorInfo()80 public Properties getProcessorInfo() 81 { 82 Properties p = TraxWrapperUtils.getTraxInfo(); 83 p.put("traxwrapper.method", "streams"); 84 p.put("traxwrapper.desc", getDescription()); 85 return p; 86 } 87 88 89 /** 90 * Actually create/initialize an underlying processor or factory. 91 * 92 * Effectively a no-op; returns null. Just forces a reset(). 93 * 94 * @param options Hashtable of options, unused. 95 * 96 * @return (Object)getProcessor() as a side-effect, this will 97 * be null if there was any problem creating the processor OR 98 * if the underlying implementation doesn't use this 99 * 100 * @throws Exception covers any underlying exceptions thrown 101 * by the actual implementation 102 */ newProcessor(Hashtable options)103 public Object newProcessor(Hashtable options) throws Exception 104 { 105 newProcessorOpts = options; 106 //@todo do we need to do any other cleanup? 107 reset(false); 108 return null; 109 } 110 111 112 /** 113 * Transform supplied xmlName file with the stylesheet in the 114 * xslName file into a resultName file. 115 * 116 * Names are assumed to be local path\filename references, and 117 * will be converted to URLs as needed for any underlying 118 * processor implementation. 119 * 120 * @param xmlName local path\filename of XML file to transform 121 * @param xslName local path\filename of XSL stylesheet to use 122 * @param resultName local path\filename to put result in 123 /* TWA - temp hack; use results dir to get path for to use for a dir to put 124 the translets 125 */ 126 /* 127 * @return array of longs denoting timing of only these parts of 128 * our operation: IDX_OVERALL, IDX_XSLBUILD, IDX_TRANSFORM 129 * 130 * @throws Exception any underlying exceptions from the 131 * wrappered processor are simply allowed to propagate; throws 132 * a RuntimeException if any other problems prevent us from 133 * actually completing the operation 134 */ transform(String xmlName, String xslName, String resultName)135 public long[] transform(String xmlName, String xslName, String resultName) 136 throws Exception 137 { 138 long startTime = 0; 139 long xslBuild = 0; 140 long transform = 0; 141 142 // java org.apache.xalan.xlstc.cmdline.Compile play1.xsl 143 // java org.apache.xalan.xlstc.cmdline.Transform play.xml play1 >stdout 144 145 // Timed: compile stylesheet class from XSL file 146 // String[] args1 = new String[2]; 147 /* TWA - commented out the following for short-term 148 Problem when local path/file is being used, somewhere a file://// prefix is 149 being appended to the filename and xsltc can't find the file even with the -u 150 So I strip off the protocol prefix and pass the local path/file 151 args1[0] = "-u"; // Using URIs 152 args1[1] = xslName; 153 */ 154 /* TWA - temporay hack to construct and pass a directory for translets */ 155 int last = resultName.lastIndexOf(FILE_SEPARATOR); 156 String tdir = resultName.substring(0, last); 157 int next = tdir.lastIndexOf(FILE_SEPARATOR); 158 String transletsdirName = tdir.substring(0, next); 159 160 String[] args1 = new String[3]; 161 args1[0] = "-d"; 162 args1[1] = transletsdirName; 163 args1[2] = xslName; 164 int idx = xslName.indexOf("file:////"); 165 if (idx != -1){ 166 xslName = new String(xslName.substring(8)); 167 args1[2] = xslName; 168 } 169 startTime = System.currentTimeMillis(); 170 /// Transformer transformer = factory.newTransformer(new StreamSource(xslName)); 171 Compile.main(args1); 172 xslBuild = System.currentTimeMillis() - startTime; 173 174 // Verify output file was created 175 // WARNING: assumption of / here, which means we assume URI not local path - needs revisiting 176 int nameStart = xslName.lastIndexOf(FILE_SEPARATOR) + 1; 177 String baseName = xslName.substring(nameStart); 178 int extStart = baseName.lastIndexOf('.'); 179 if (extStart > 0) { 180 baseName = baseName.substring(0, extStart); 181 } 182 183 // Replace illegal class name chars with underscores. 184 StringBuffer sb = new StringBuffer(baseName.length()); 185 char charI = baseName.charAt(0); 186 sb.append(Character.isJavaLetter(charI) ? charI :CLEAN_CHAR); 187 for (int i = 1; i < baseName.length(); i++) { 188 charI = baseName.charAt(i); 189 sb.append(Character.isJavaLetterOrDigit(charI) ? charI :CLEAN_CHAR); 190 } 191 baseName = sb.toString(); 192 193 // Untimed: Apply any parameters needed 194 // applyParameters(transformer); 195 196 // Timed: read/build xml, transform, and write results 197 198 /* TWA - I don't see how this could have worked, there is no -s option in DefaultRun 199 so passing it in the args2 caused usage messages to be output. 200 Also, we shouldn't use the -u option unless we are really using URLs, 201 I'm just trying to get it to work with local path/files. With or without the 202 -u option, the files were getting a file://// prefix with caused them to be not found 203 String[] args2 = new String[3]; 204 args2[0] = "-s"; // Don't allow System.exit 205 args2[1] = "-u"; // Using URIs 206 args2[2] = xmlName; 207 args2[3] = baseName; // Just basename of the .class file, without the .class 208 // Note that . must be on CLASSPATH to work! 209 */ 210 211 String[] tempParam = makeParamArray(); 212 String[] args2 = new String[2 + tempParam.length]; 213 args2[0] = xmlName; 214 int idx2 = xmlName.indexOf("file:////"); 215 if (idx2 != -1){ 216 args2[0] = new String(xmlName.substring(8)); 217 } 218 args2[1] = baseName; 219 System.arraycopy(tempParam, 0, args2, 2, tempParam.length); 220 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 221 PrintStream newSystemOut = new PrintStream(baos); 222 PrintStream saveSystemOut = System.out; 223 startTime = System.currentTimeMillis(); 224 // transformer.transform(new StreamSource(xmlName), new StreamResult(resultName)); 225 try 226 { 227 // Capture System.out into our byte array 228 System.setOut(new PrintStream(baos)); 229 Transform.main(args2); 230 } 231 finally 232 { 233 // Be sure to restore System stuff! 234 System.setOut(saveSystemOut); 235 } 236 // Writing data should really go in separate timing loop 237 FileOutputStream fos = new FileOutputStream(resultName); 238 fos.write(baos.toByteArray()); 239 fos.close(); 240 transform = System.currentTimeMillis() - startTime; 241 242 File compiledXslClass = new File(baseName + ".class"); 243 //@todo WARNING! We REALLY need to clean up the name*.class files when we're done!!! -sc 244 // TWA - we should probably use the -d option to put them in a desired directory first 245 // I commented out the delete, to see if the translets were getting compiled 246 // if (compiledXslClass.exists()) 247 // compiledXslClass.delete(); 248 249 long[] times = getTimeArray(); 250 times[IDX_OVERALL] = xslBuild + transform; 251 times[IDX_XSLBUILD] = xslBuild; 252 times[IDX_TRANSFORM] = transform; 253 return times; 254 } 255 makeParamArray()256 private String[] makeParamArray() { 257 if (m_params == null) { 258 return new String[0]; 259 } 260 String[] params = new String[m_params.size()]; 261 Iterator iter = m_params.entrySet().iterator(); 262 int i = 0; 263 while (iter.hasNext()) { 264 Map.Entry entry = (Map.Entry) iter.next(); 265 params[i++] = entry.getKey() + "=" + entry.getValue(); 266 } 267 return params; 268 } 269 270 /** 271 * Pre-build/pre-compile a stylesheet. 272 * 273 * Although the actual mechanics are implementation-dependent, 274 * most processors have some method of pre-setting up the data 275 * needed by the stylesheet itself for later use in transforms. 276 * In TrAX/javax.xml.transform, this equates to creating a 277 * Templates object. 278 * 279 * Sets isStylesheetReady() to true if it succeeds. Users can 280 * then call transformWithStylesheet(xmlName, resultName) to 281 * actually perform a transformation with this pre-built 282 * stylesheet. 283 * 284 * @param xslName local path\filename of XSL stylesheet to use 285 * 286 * @return array of longs denoting timing of only these parts of 287 * our operation: IDX_OVERALL, IDX_XSLBUILD 288 * 289 * @throws Exception any underlying exceptions from the 290 * wrappered processor are simply allowed to propagate; throws 291 * a RuntimeException if any other problems prevent us from 292 * actually completing the operation 293 * 294 * @see #transformWithStylesheet(String xmlName, String resultName) 295 */ buildStylesheet(String xslName)296 public long[] buildStylesheet(String xslName) throws Exception 297 { 298 throw new RuntimeException("buildStylesheet not implemented yet!"); 299 } 300 301 302 /** 303 * Transform supplied xmlName file with a pre-built/pre-compiled 304 * stylesheet into a resultName file. 305 * 306 * User must have called buildStylesheet(xslName) beforehand, 307 * obviously. 308 * Names are assumed to be local path\filename references, and 309 * will be converted to URLs as needed. 310 * 311 * @param xmlName local path\filename of XML file to transform 312 * @param resultName local path\filename to put result in 313 * 314 * @return array of longs denoting timing of only these parts of 315 * our operation: IDX_OVERALL, IDX_XSLBUILD, IDX_TRANSFORM 316 * 317 * @throws Exception any underlying exceptions from the 318 * wrappered processor are simply allowed to propagate; throws 319 * a RuntimeException if any other problems prevent us from 320 * actually completing the operation; throws an 321 * IllegalStateException if isStylesheetReady() == false. 322 * 323 * @see #buildStylesheet(String xslName) 324 */ transformWithStylesheet(String xmlName, String resultName)325 public long[] transformWithStylesheet(String xmlName, String resultName) 326 throws Exception 327 { 328 if (!isStylesheetReady()) 329 throw new IllegalStateException("transformWithStylesheet() when isStylesheetReady() == false"); 330 331 throw new RuntimeException("transformWithStylesheet not implemented yet!"); 332 } 333 334 335 /** 336 * Transform supplied xmlName file with a stylesheet found in an 337 * xml-stylesheet PI into a resultName file. 338 * 339 * Names are assumed to be local path\filename references, and 340 * will be converted to URLs as needed. Implementations will 341 * use whatever facilities exist in their wrappered processor 342 * to fetch and build the stylesheet to use for the transform. 343 * 344 * @param xmlName local path\filename of XML file to transform 345 * @param resultName local path\filename to put result in 346 * 347 * @return array of longs denoting timing of only these parts of 348 * our operation: IDX_OVERALL, IDX_XSLREAD (time to find XSL 349 * reference from the xml-stylesheet PI), IDX_XSLBUILD, (time 350 * to then build the Transformer therefrom), IDX_TRANSFORM 351 * 352 * @throws Exception any underlying exceptions from the 353 * wrappered processor are simply allowed to propagate; throws 354 * a RuntimeException if any other problems prevent us from 355 * actually completing the operation 356 */ transformEmbedded(String xmlName, String resultName)357 public long[] transformEmbedded(String xmlName, String resultName) 358 throws Exception 359 { 360 throw new RuntimeException("transformEmbedded not implemented yet!"); 361 } 362 363 364 /** 365 * Reset our parameters and wrapper state, and optionally 366 * force creation of a new underlying processor implementation. 367 * 368 * This always clears our built stylesheet and any parameters 369 * that have been set. If newProcessor is true, also forces a 370 * re-creation of our underlying processor as if by calling 371 * newProcessor(). 372 * 373 * @param newProcessor if we should reset our underlying 374 * processor implementation as well 375 */ reset(boolean newProcessor)376 public void reset(boolean newProcessor) 377 { 378 super.reset(newProcessor); // clears indent and parameters 379 m_stylesheetReady = false; 380 // builtTemplates = null; 381 if (newProcessor) 382 { 383 try 384 { 385 newProcessor(newProcessorOpts); 386 } 387 catch (Exception e) 388 { 389 //@todo Hmm: what should we do here? 390 } 391 } 392 } 393 394 /** 395 * Apply a single parameter to a Transformer. 396 * 397 * WARNING: Not implemented! 27-Apr-01 398 * 399 * @param passThru to be passed to each applyParameter() method 400 * call - for TrAX, you might pass a Transformer object. 401 * @param namespace for the parameter, may be null 402 * @param name for the parameter, should not be null 403 * @param value for the parameter, may be null 404 */ applyParameter(Object passThru, String namespace, String name, Object value)405 protected void applyParameter(Object passThru, String namespace, 406 String name, Object value) 407 { 408 /* WARNING: Not implemented! 27-Apr-01 */ 409 } 410 } 411