xref: /aosp_15_r20/external/apache-xml/test/java/src/org/apache/qetest/xslwrapper/XsltcMainWrapper.java (revision 1212f9a0ffdc28482b8821715d2222bf16dc14e2)
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