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 23 import java.util.Hashtable; 24 import java.util.Properties; 25 26 import org.apache.qetest.Configurable; 27 28 /** 29 * Helper interface to wrapper various XSLT processors for testing. 30 * 31 * A TransformWrapper wraps a particular 'flavor' of XSLT processing. 32 * This includes both a particular XSLT implementation, such as 33 * Xalan or Saxon, as well as a particular method to perform 34 * processing, like using streams or DOMs to perform transforms. 35 * 36 * As an important side effect, this class should return timing 37 * information about the steps done to perform the transformation. 38 * Note that exactly what is timed and how it's timed should be 39 * clearly documented in implementing classes! 40 * 41 * This is not a general-purpose wrapper for doing XSLT 42 * transformations: for that, you might as well use the real 43 * javax.xml.transform package itself. However this does allow 44 * many conformance and performance tests to run comparatively 45 * between different flavors of processors. 46 * 47 * TransformWrapper is a bit of an awkward name, but I wanted to 48 * keep it separate from the pre-existing ProcessorWrapper that 49 * this replaces so we can ensure stability for Xalan testing 50 * while updating to this new class. 51 * 52 * @author Shane Curcuru 53 * @version $Id$ 54 */ 55 public interface TransformWrapper extends Configurable 56 { 57 58 /** 59 * Timing constant: this operation did not attempt to time this 60 * item, or the item is not appropriate for this case. 61 * 62 * Currently we return a similar array of longs from every 63 * timed call, however buildStylesheet() would obviously not 64 * have entries for xmlread/xmlbuild times. This value will 65 * be used for any times not used, since a negative number is 66 * clearly inappropriate for a time duration (until someone 67 * does some heavy relativistic optimizations). 68 */ 69 public static final long TIME_UNUSED = -2L; 70 71 72 /** 73 * Timing index: overall time to complete operation. 74 * 75 * This time, which is always the first long[] array item in 76 * any timed call, is the overall amount of time taken to 77 * complete the whole operation, from start to finish. This 78 * may include time in reading the inputs from disk and 79 * writing the outputs to disk, as well as any other time 80 * taken by the processor to complete other portions of the 81 * task. 82 * 83 * In general, this should not include overhead for the wrapper 84 * itself, and notably will not include time taken up while 85 * setting parameters or other attributes into the underlying 86 * processor (which are hopefully minor compared to other items). 87 * 88 * Note that other timing indexes may be filled in as 89 * TIME_UNUSED by calls that don't time anything useful. E.g. 90 * buildStylesheet will not return data for xml-related times. 91 */ 92 public static final int IDX_OVERALL = 0; 93 94 95 /** 96 * Timing index: time spend reading an XSL file into memory. 97 * 98 * This should be the time spent just reading the XSL file from 99 * disk into memory, to attempt to isolate disk I/O issues. 100 * Note that implementations should carefully document exactly 101 * what this operation does: just reads the data into a 102 * ByteStream, or actually builds a DOM, or whatever. 103 */ 104 public static final int IDX_XSLREAD = 1; 105 106 107 /** 108 * Timing index: time to build the stylesheet. 109 * 110 * This should include the time it takes the processor 111 * implementation to take an XSL source and turn it into 112 * whatever useable form it wants. 113 * 114 * In TrAX, this would normally correspond to the time it 115 * takes the newTemplates() call to return when handed a 116 * StreamSource(ByteStream) object. Normally this would 117 * be a ByteStream already in memory, but some wrappers 118 * may not allow separating the xslread time (which would 119 * be reading the file from disk into a ByteStream in memory) 120 * from this xslbuild time. 121 */ 122 public static final int IDX_XSLBUILD = 2; 123 124 125 /** 126 * Timing index: time spend reading an XML file into memory. 127 * 128 * This should be the time spent just reading the XML file from 129 * disk into memory, to attempt to isolate disk I/O issues. 130 * Note that implementations should carefully document exactly 131 * what this operation does: just reads the data into a 132 * ByteStream, or actually builds a DOM, or whatever. 133 */ 134 public static final int IDX_XMLREAD = 3; 135 136 137 /** 138 * Timing index: time to build the XML document. 139 * 140 * This should include the time it takes the processor 141 * implementation to take an XML source and turn it into 142 * whatever useable form it wants. 143 * 144 * In TrAX, this would normally only correspond to the time 145 * taken to create a DOMSource from an in-memory ByteStream. 146 * The Xalan-C version may use this more than the Java version. 147 */ 148 public static final int IDX_XMLBUILD = 4; 149 150 151 /** 152 * Timing index: time to complete the transform from sources. 153 * 154 * Normally this should be just the time to complete outputting 155 * the whole result tree from a transform from in-memory sources. 156 * Obviously different wrapper implementations will measure 157 * slightly different things in this field, which needs to be 158 * clearly documented. 159 * 160 * For example, in TrAX, this would correspond to doing a 161 * transformer.transform(xmlSource, StreamResult(ByteStream)) 162 * where the ByteStream is in memory. A separate time should be 163 * recorded for resultwrite that actually puts the stream out 164 * to disk. 165 * 166 * Note that some wrappers may not be able to separate the 167 * transform time from the resultwrite time: for example a 168 * wrapper that wants to test with new StreamResult(URL). 169 */ 170 public static final int IDX_TRANSFORM = 5; 171 172 173 /** 174 * Timing index: time to write the result tree to disk. 175 * 176 * See discussion in IDX_TRANSFORM. This may not always 177 * be used. 178 */ 179 public static final int IDX_RESULTWRITE = 6; 180 181 182 /** 183 * Timing index: Time from beginning of transform from sources 184 * until the first bytes of the result tree come out. 185 * 186 * Future use. This is for testing pipes and server 187 * applications, where the user is concerned about latency and 188 * throughput. This will measure how responsive the processor 189 * appears to be at first (but not necessarily how long it 190 * takes to write the whole the result tree). 191 */ 192 public static final int IDX_FIRSTLATENCY = 7; 193 194 195 /** 196 * URL for set/getAttribute: should be an integer to set 197 * for the output indent of the processor. 198 * 199 * This is a common enough attribute that most wrapper 200 * implementations should be able to support it in a 201 * straightforward manner. 202 */ 203 public static final String ATTRIBUTE_INDENT = 204 "http://xml.apache.org/xalan/wrapper/indent"; 205 206 207 /** 208 * URL for set/getAttribute: should be an Object to attempt 209 * to set as a diagnostic log/stream for the processor. 210 * 211 * //@todo see if there's a fairly generic way to implement 212 * this that will get at least some data from all common 213 * processor implementations: either by using some native 214 * diagnostics PrintStream the processor provides, or by 215 * implementing a simple LoggingErrorListener, etc. 216 */ 217 public static final String ATTRIBUTE_DIAGNOSTICS = 218 "http://xml.apache.org/xalan/wrapper/diagnostics"; 219 220 221 /** 222 * Marker for Attributes to set on Processors. 223 * 224 * Options that startWith() this constant will actually be 225 * attempted to be set onto our underlying processor/transformer. 226 */ 227 public static final String SET_PROCESSOR_ATTRIBUTES = 228 "Processor.setAttribute."; 229 230 231 /** 232 * Get a specific description of the wrappered processor. 233 * 234 * @return specific description of the underlying processor or 235 * transformer implementation: this should include both the 236 * general product name, as well as specific version info. If 237 * possible, should be implemented without actively creating 238 * an underlying processor. 239 */ getProcessorInfo()240 public Properties getProcessorInfo(); 241 242 243 /** 244 * Actually create/initialize an underlying processor or factory. 245 * 246 * For TrAX/javax.xml.transform implementations, this creates 247 * a new TransformerFactory. For Xalan-J 1.x this creates an 248 * XSLTProcessor. Other implmentations may or may not actually 249 * do any work in this method. 250 * 251 * @param options Hashtable of options, possibly specific to 252 * that implementation. For future use. 253 * 254 * @return (Object)getProcessor() as a side-effect, this will 255 * be null if there was any problem creating the processor OR 256 * if the underlying implementation doesn't use this 257 * 258 * @throws Exception covers any underlying exceptions thrown 259 * by the actual implementation 260 */ newProcessor(Hashtable options)261 public Object newProcessor(Hashtable options) throws Exception; 262 263 264 /** 265 * Transform supplied xmlName file with the stylesheet in the 266 * xslName file into a resultName file. 267 * 268 * Names are assumed to be local path\filename references, and 269 * will be converted to URLs as needed for any underlying 270 * processor implementation. 271 * 272 * @param xmlName local path\filename of XML file to transform 273 * @param xslName local path\filename of XSL stylesheet to use 274 * @param resultName local path\filename to put result in 275 * 276 * @return array of longs denoting timing of various parts of 277 * our operation; [0] is always the total end-to-end time, and 278 * other array indicies are represented by IDX_* constants 279 * 280 * @throws Exception any underlying exceptions from the 281 * wrappered processor are simply allowed to propagate; throws 282 * a RuntimeException if any other problems prevent us from 283 * actually completing the operation 284 */ transform(String xmlName, String xslName, String resultName)285 public long[] transform(String xmlName, String xslName, String resultName) 286 throws Exception; 287 288 289 /** 290 * Pre-build/pre-compile a stylesheet. 291 * 292 * Although the actual mechanics are implementation-dependent, 293 * most processors have some method of pre-setting up the data 294 * needed by the stylesheet itself for later use in transforms. 295 * In TrAX/javax.xml.transform, this equates to creating a 296 * Templates object. 297 * 298 * Sets isStylesheetReady() to true if it succeeds. Users can 299 * then call transformWithStylesheet(xmlName, resultName) to 300 * actually perform a transformation with this pre-built 301 * stylesheet. 302 * 303 * @param xslName local path\filename of XSL stylesheet to use 304 * 305 * @return array of longs denoting timing of various parts of 306 * our operation; [0] is always the total end-to-end time, and 307 * other array indicies are represented by constants 308 * 309 * @throws Exception any underlying exceptions from the 310 * wrappered processor are simply allowed to propagate; throws 311 * a RuntimeException if any other problems prevent us from 312 * actually completing the operation 313 * 314 * @see #transformWithStylesheet(String xmlName, String resultName) 315 */ buildStylesheet(String xslName)316 public long[] buildStylesheet(String xslName) throws Exception; 317 318 319 /** 320 * Reports if a pre-built/pre-compiled stylesheet is ready; 321 * presumably built by calling buildStylesheet(xslName). 322 * 323 * @return true if one is ready; false otherwise 324 * 325 * @see #buildStylesheet(String xslName) 326 */ isStylesheetReady()327 public boolean isStylesheetReady(); 328 329 330 /** 331 * Transform supplied xmlName file with a pre-built/pre-compiled 332 * stylesheet into a resultName file. 333 * 334 * User must have called buildStylesheet(xslName) beforehand, 335 * obviously. 336 * Names are assumed to be local path\filename references, and 337 * will be converted to URLs as needed. 338 * 339 * @param xmlName local path\filename of XML file to transform 340 * @param resultName local path\filename to put result in 341 * 342 * @return array of longs denoting timing of various parts of 343 * our operation; [0] is always the total end-to-end time, and 344 * other array indicies are represented by constants 345 * 346 * @throws Exception any underlying exceptions from the 347 * wrappered processor are simply allowed to propagate; throws 348 * a RuntimeException if any other problems prevent us from 349 * actually completing the operation; throws an 350 * IllegalStateException if isStylesheetReady() == false. 351 * 352 * @see #buildStylesheet(String xslName) 353 */ transformWithStylesheet(String xmlName, String resultName)354 public long[] transformWithStylesheet(String xmlName, String resultName) 355 throws Exception; 356 357 358 /** 359 * Transform supplied xmlName file with a stylesheet found in an 360 * xml-stylesheet PI into a resultName file. 361 * 362 * Names are assumed to be local path\filename references, and 363 * will be converted to URLs as needed. Implementations will 364 * use whatever facilities exist in their wrappered processor 365 * to fetch and build the stylesheet to use for the transform. 366 * 367 * @param xmlName local path\filename of XML file to transform 368 * @param resultName local path\filename to put result in 369 * 370 * @return array of longs denoting timing of various parts of 371 * our operation; [0] is always the total end-to-end time, and 372 * other array indicies are represented by constants 373 * 374 * @throws Exception any underlying exceptions from the 375 * wrappered processor are simply allowed to propagate; throws 376 * a RuntimeException if any other problems prevent us from 377 * actually completing the operation 378 */ transformEmbedded(String xmlName, String resultName)379 public long[] transformEmbedded(String xmlName, String resultName) 380 throws Exception; 381 382 383 /** 384 * Set a stylesheet parameter for use in later transforms. 385 * 386 * This method merely stores the triple for use later in a 387 * transform operation. Note that the actual mechanisims for 388 * setting parameters in implementation differ, especially with 389 * regards to namespaces. 390 * 391 * Note that the namespace may not contain the "{" or "}" 392 * characters, since these would be illegal XML namespaces 393 * anyways; an IllegalArgumentException will be thrown; also 394 * the name must not be null. 395 * 396 * @param namespace for the parameter, must not contain {} 397 * @param name of the parameter, must not be null 398 * @param value of the parameter 399 * 400 * @throws IllegalArgumentException thrown if the namespace 401 * or name appears to be illegal. 402 */ setParameter(String namespace, String name, Object value)403 public void setParameter(String namespace, String name, Object value) 404 throws IllegalArgumentException; 405 406 407 /** 408 * Get a parameter that was set with setParameter. 409 * 410 * Only returns parameters set locally, not parameters exposed 411 * by the underlying processor implementation. Not terribly 412 * useful but I like providing gets for any sets I define. 413 * 414 * @param namespace for the parameter, must not contain {} 415 * @param name of the parameter, must not be null 416 * 417 * @return value of the parameter; null if not found 418 */ getParameter(String namespace, String name)419 public Object getParameter(String namespace, String name); 420 421 422 /** 423 * Reset our parameters and wrapper state, and optionally 424 * force creation of a new underlying processor implementation. 425 * 426 * This always clears our built stylesheet and any parameters 427 * that have been set. If newProcessor is true, also forces a 428 * re-creation of our underlying processor as if by calling 429 * newProcessor(). 430 * 431 * @param newProcessor if we should reset our underlying 432 * processor implementation as well 433 */ reset(boolean newProcessor)434 public void reset(boolean newProcessor); 435 } 436