• 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 
22 /*
23  *
24  * CmdlineTestlet.java
25  *
26  */
27 package org.apache.qetest.xsl;
28 
29 import java.io.BufferedReader;
30 import java.io.File;
31 import java.io.InputStreamReader;
32 import java.util.Hashtable;
33 
34 import org.apache.qetest.Datalet;
35 import org.apache.qetest.Logger;
36 import org.apache.qetest.ThreadedStreamReader;
37 import org.apache.qetest.xslwrapper.TransformWrapper;
38 
39 /**
40  * Testlet for conformance testing of xsl stylesheet files using
41  * a command line interface instead of a TransformWrapper.
42  *
43  * This class provides a default algorithim for testing XSLT
44  * processsors from the command line.  Subclasses define the
45  * exact command line args, etc. used for different products.
46  *
47  * @author Shane_Curcuru@lotus.com
48  * @version $Id$
49  */
50 public class CmdlineTestlet extends StylesheetTestlet
51 {
52     // Initialize our classname for TestletImpl's main() method
53     static { thisClassName = "org.apache.qetest.xsl.CmdlineTestlet"; }
54 
55     // Initialize our defaultDatalet
56     { defaultDatalet = (Datalet)new StylesheetDatalet(); }
57 
58     /**
59      * Accesor method for a brief description of this test.
60      *
61      * @return String describing what this CmdlineTestlet does.
62      */
getDescription()63     public String getDescription()
64     {
65         return "CmdlineTestlet";
66     }
67 
68     /**
69      * Parameter: Actual name of external program to call.
70      */
71     public static final String OPT_PROGNAME = "progName";
72 
73     /**
74      * Default Actual name of external program to call.
75      * @return TestXSLT, the Xalan-C command line.
76      */
getDefaultProgName()77     public String getDefaultProgName()
78     {
79         return "TestXSLT";
80     }
81 
82     /**
83      * Path to external program to call; default is none.
84      */
85     public static final String OPT_PROGPATH = "progPath";
86 
87 
88     /**
89      * Worker method to actually perform the transform;
90      * overriden to use command line processing.
91      *
92      * Logs out applicable info; attempts to perform transformation.
93      *
94      * @param datalet to test with
95      * @param transformWrapper to have perform the transform
96      * @throws allows any underlying exception to be thrown
97      */
testDatalet(StylesheetDatalet datalet, TransformWrapper transformWrapper)98     protected void testDatalet(StylesheetDatalet datalet, TransformWrapper transformWrapper)
99             throws Exception
100     {
101         String[] defaultArgs = new String[0];   // Currently unused
102         String[] args = getProgramArguments(datalet, defaultArgs);
103 
104         StringBuffer argBuf = new StringBuffer();
105         for (int i = 0; i < args.length; i++)
106         {
107             argBuf.append(args[i]);
108             argBuf.append(" ");
109         }
110         //@todo Should we log a custom logElement here instead?
111         logger.logMsg(Logger.TRACEMSG, "cmdline executing: " + argBuf.toString());
112 
113         // Declare variables ahead of time to minimize latency
114         long startTime = 0;
115         long overallTime = 0;
116 
117         // Use our worker method to execute the process, which
118         //  runs the test via the command line
119         startTime = System.currentTimeMillis();
120         execProcess(args, null);
121         overallTime = System.currentTimeMillis() - startTime;
122 
123     }
124 
125 
126     /**
127      * Worker method to get list of arguments specific to this program.
128      *
129      * <p>Must be overridden for different processors, obviously.
130      * This implementation returns the args for Xalan-C TestXSLT</p>
131      *
132      * @param program path\name of program to Runtime.exec()
133      * @param defaultArgs any additional arguments to pass
134      * @return String array of arguments suitable to pass to
135      * Runtime.exec()
136      */
getProgramArguments(StylesheetDatalet datalet, String[] defaultArgs)137     public String[] getProgramArguments(StylesheetDatalet datalet, String[] defaultArgs)
138     {
139         final int NUMARGS = 7;
140         String[] args = new String[defaultArgs.length + NUMARGS];
141         String progName = datalet.options.getProperty(OPT_PROGNAME, getDefaultProgName());
142         String progPath = datalet.options.getProperty(OPT_PROGPATH);
143         if ((null != progPath) && (progPath.length() > 0))
144         {
145             args[0] = progPath + File.separator + progName;
146         }
147         else
148         {
149             // Pesume the program is on the PATH already...
150             args[0] = progName;
151         }
152 
153         // Default args for Xalan-C TestXSLT
154         args[1] = "-in";
155         args[2] = datalet.xmlName;
156         args[3] = "-xsl";
157         args[4] = datalet.inputName;
158         args[5] = "-out";
159         args[6] = datalet.outputName;
160 
161         if (defaultArgs.length > 0)
162             System.arraycopy(defaultArgs, 0, args, NUMARGS, defaultArgs.length);
163 
164         return args;
165     }
166 
167 
168     /**
169      * Worker method to shell out an external process.
170      *
171      * <p>Does a simple capturing of the out and err streams from
172      * the process and logs them out.  Inherits the same environment
173      * that the current JVM is in.</p>
174      *
175      * @param cmdline actual command line to run, including program name
176      * @param environment passed as-is to Process.run
177      * @return return value from program
178      * @exception Exception may be thrown by Runtime.exec
179      */
execProcess(String[] cmdline, String[] environment)180     public void execProcess(String[] cmdline, String[] environment)
181             throws Exception
182     {
183         if ((cmdline == null) || (cmdline.length < 1))
184         {
185             logger.checkFail("execProcess called with null/blank arguments!");
186             return;
187         }
188 
189         int bufSize = 2048; // Arbitrary bufSize seems to work well
190         ThreadedStreamReader outReader = new ThreadedStreamReader();
191         ThreadedStreamReader errReader = new ThreadedStreamReader();
192         Runtime r = Runtime.getRuntime();
193         java.lang.Process proc = null;  // Fully declare to not conflict with org.apache.xalan.xslt.Process
194 
195         // Actually begin executing the program
196         logger.logMsg(Logger.TRACEMSG, "execProcess starting " + cmdline[0]);
197 
198         proc = r.exec(cmdline, environment);
199 
200         // Immediately begin capturing any output therefrom
201         outReader.setInputStream(
202             new BufferedReader(
203                 new InputStreamReader(proc.getInputStream()), bufSize));
204         errReader.setInputStream(
205             new BufferedReader(
206                 new InputStreamReader(proc.getErrorStream()), bufSize));
207 
208         // Start two threads off on reading the System.out and System.err from proc
209         outReader.start();
210         errReader.start();
211         int processReturnVal = -2; // HACK the default
212         try
213         {
214             // Wait for the process to exit normally
215             processReturnVal = proc.waitFor();
216         }
217         catch (InterruptedException ie1)
218         {
219             logger.logThrowable(Logger.ERRORMSG, ie1,
220                                   "execProcess proc.waitFor() threw");
221         }
222 
223         // Now that we're done, presumably the Readers are also done
224         StringBuffer sysOut = null;
225         StringBuffer sysErr = null;
226         try
227         {
228             outReader.join();
229             sysOut = outReader.getBuffer();
230         }
231         catch (InterruptedException ie2)
232         {
233             logger.logThrowable(Logger.ERRORMSG, ie2, "Joining outReader threw");
234         }
235 
236         try
237         {
238             errReader.join();
239             sysErr = errReader.getBuffer();
240         }
241         catch (InterruptedException ie3)
242         {
243             logger.logThrowable(Logger.ERRORMSG, ie3, "Joining errReader threw");
244         }
245 
246         checkOutputStreams(cmdline, sysOut, sysErr, processReturnVal);
247     }
248 
249 
250     /**
251      * Worker method to evaluate the System.out/.err streams of
252      * a particular processor.
253      *
254      * @param cmdline that was used for execProcess
255      * @param outBuf buffer from execProcess' System.out
256      * @param errBuf buffer from execProcess' System.err
257      * @param processReturnVal from execProcess
258      */
checkOutputStreams(String[] cmdline, StringBuffer outBuf, StringBuffer errBuf, int processReturnVal)259     protected void checkOutputStreams(String[] cmdline, StringBuffer outBuf,
260             StringBuffer errBuf, int processReturnVal)
261     {
262         Hashtable attrs = new Hashtable();
263         attrs.put("program", cmdline[0]);
264         attrs.put("returnVal", String.valueOf(processReturnVal));
265 
266         StringBuffer buf = new StringBuffer();
267         if ((null != errBuf) && (errBuf.length() > 0))
268         {
269             buf.append("<system-err>");
270             buf.append(errBuf);
271             buf.append("</system-err>\n");
272         }
273         if ((null != outBuf) && (outBuf.length() > 0))
274         {
275             buf.append("<system-out>");
276             buf.append(outBuf);
277             buf.append("</system-out>\n");
278         }
279         logger.logElement(Logger.INFOMSG, "checkOutputStreams", attrs, buf.toString());
280         attrs = null;
281         buf = null;
282     }
283 
284 
285     /**
286      * Worker method to get a TransformWrapper; overridden as no-op.
287      *
288      * @param datalet to test with
289      * @return null; CmdlineTestlet does not use this
290      */
getTransformWrapper(StylesheetDatalet datalet)291     protected TransformWrapper getTransformWrapper(StylesheetDatalet datalet)
292     {
293         return null;
294     }
295 }  // end of class CmdlineTestlet
296 
297