• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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