blob: ab2fb4c5b904680c48e2aa5d04e55ee943e29ae7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id$
*/
package org.apache.qetest.xsl;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Vector;
import org.apache.qetest.Logger;
/**
* Simple services for getting lists of StylesheetDatalets.
*
*
* @author shane_curcuru@us.ibm.com
* @version $Id$
*/
public abstract class StylesheetDataletManager // provide static services only
{
/**
* Token in xsl file denoting the text of an expected exception.
* Used in getInfoItem.
*/
public static final String INFOITEM_EXPECTED_EXCEPTION = "ExpectedException:";
/**
* Get specified information about the datalet.
*
* <p>Note that different kinds of information may be read
* or discovered in different ways.</p>
*
* <p>Currently only implemented for
* INFOITEM_EXPECTED_EXCEPTION.</p>
*
* @param logger to report problems to
* @param datalet to get information about
* @param infoItem to get information about
* @return Vector of object(s) of appropriate type;
* or null if error
*/
public static Vector getInfoItem(Logger logger, StylesheetDatalet datalet, String infoItem)
{
if ((null == datalet) || (null == infoItem))
{
logger.logMsg(Logger.ERRORMSG, "getTestInfo called with null datalet or infoItem!");
return null;
}
if (INFOITEM_EXPECTED_EXCEPTION.equals(infoItem))
{
return getExpectedException(logger, datalet);
}
else
{
logger.logMsg(Logger.WARNINGMSG, "getTestInfo unsupported infoItem: " + infoItem);
return null;
}
}
/**
* Worker method to get expected exception text about a stylesheet.
*
* Currently parses the inputDir stylesheet for a line that contains
* EXPECTED_EXCEPTION inside an xsl comment, on a single line, and
* trims off the closing comment -->.
* Future work: allow options on datalet to specify some other
* expected data in another format - a whole Throwable object to
* compare to, or a stacktrace, etc.
*
* @author Shane Curcuru
* @param d Datalet that contains info about the exception
* @return Vector of Strings denoting toString of exception(s)
* we might expect - any one of them will pass; null if error
*/
protected static Vector getExpectedException(Logger logger, StylesheetDatalet d)
{
final String EXPECTED_EXCEPTION_END = "-->";
Vector v = null;
// Read in the testName file to see if it's expecting something
try
{
FileReader fr = new FileReader(d.inputName);
BufferedReader br = new BufferedReader(fr);
for (;;)
{
String inbuf = br.readLine();
if (inbuf == null)
break; // end of file, break out and return
int idx = inbuf.indexOf(INFOITEM_EXPECTED_EXCEPTION);
if (idx < 0)
continue; // not on this line, keep going
// The expected exception.getMessage is the rest of the line...
String expExc = inbuf.substring(idx + INFOITEM_EXPECTED_EXCEPTION.length(),
inbuf.length());
// ... less the trailing " -->" comment end; trimmed
int endComment = expExc.indexOf(EXPECTED_EXCEPTION_END);
if (endComment > -1)
expExc = expExc.substring(0, endComment).trim();
else
expExc = expExc.trim();
if (null == v)
v = new Vector(); // only create if needed
v.addElement(expExc);
// Continue reading the file for more potential
// expected exception strings - read them all
//@todo optimization: stop parsing after xx lines?
} // end for (;;)
}
catch (java.io.IOException ioe)
{
logger.logMsg(Logger.ERRORMSG, "getExpectedException() threw: "
+ ioe.toString());
return null;
}
return v;
}
/** '[' character, first char in first line of xsltmark fileList. */
public static final String XSLTMARK_CHAR = "[";
/** '#' character, comment char in qetest fileList. */
public static final String QETEST_COMMENT_CHAR = "#";
/**
* Read in a file specifying a list of files to test.
* <p>File format is determined from first line in file,
* which is a little bit dangerous!</p>
* <p>If first line starts with '[', it's an xsltmark-style
* fileList, otherwise it's a qetest-style fileList.</p>
*
* @param logger to report problems to
* @param fileName String; name of the file
* @param desc description; caller's copy changed
* @param defaults default properties to potentially add to each datalet
* @return Vector of StylesheetDatalets, or null if error
*/
public static Vector readFileList(Logger logger, String fileName, String desc, Properties defaults)
{
// Verify the file is there
File f = new File(fileName);
if (!f.exists())
{
logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName
+ " does not exist!");
return null;
}
BufferedReader br = null;
String line = null;
try
{
br = new BufferedReader(new FileReader(f));
line = br.readLine(); // read just first line
}
catch (IOException ioe)
{
logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName
+ " threw: " + ioe.toString());
return null;
}
// Verify the first line
if (line == null)
{
logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName
+ " appears to be blank!");
return null;
}
// Determine which kind of fileList this is
// we support the 'native' org.apache.qetest format, and
// alternately the .ini file format used in xsltmark
Vector vec = null;
if (line.startsWith(XSLTMARK_CHAR))
{
// This is an xsltmark .ini style file
vec = readXsltmarkFileList(logger, br, line, fileName, desc, defaults);
}
else if (line.startsWith(QETEST_COMMENT_CHAR))
{
// This is a native qetest style file
vec = readQetestFileList(logger, br, line, fileName, desc, defaults);
}
else
{
logger.logMsg(Logger.WARNINGMSG, "readFileList: " + fileName
+ " could not determine file type; assuming qetest!");
vec = readQetestFileList(logger, br, line, fileName, desc, defaults);
}
if (vec.size() == 0)
{
logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName
+ " did not have any non-comment lines!");
return null;
}
return vec;
}
/**
* Read in a qetest fileList specifying a list of files to test.
* <p>File format is pretty simple:</p>
* <ul>
* <li># first line of comments is copied into desc</li>
* <li># beginning a line is a comment</li>
* <li># rest of lines are whitespace delimited filenames and options</li>
* <li>inputName xmlName outName goldName flavor options...</li>
* <li><b>Note:</b> see {@link StylesheetDatalet} for
* details on how the file lines are parsed!</li>
* </ul>
* <p>Most items are optional, but not having them may result
* in validation oddities. Future work would be to coordinate
* this with various Datalet's implementations of .load() so
* that Datalets can do better defaulting of non-provided
* items; or maybe so that a user can specific a default 'mask'
* of values to use for unspecified items.</p>
*
* @param logger to report problems to
* @param br BufferedReader to read from
* @param firstLine already read from br
* @param fileName String; name of the file
* @param desc to use of this file
* @param defaults default properties to potentially add to each datalet
* @return Vector of StylesheetDatalets, or null if error
*/
protected static Vector readQetestFileList(Logger logger, BufferedReader br,
String firstLine, String fileName,
String desc, Properties defaults)
{
final String ABSOLUTE = "absolute";
final String RELATIVE = "relative";
Vector vec = new Vector();
String line = firstLine;
// Check if the first line is a comment
if (line.startsWith(QETEST_COMMENT_CHAR))
{
// Save it as the description
desc = line;
// Parse the next line
try
{
line = br.readLine();
}
catch (IOException ioe)
{
logger.logMsg(Logger.ERRORMSG, "readQetestFileList: "
+ fileName + " threw: " + ioe.toString());
return null;
}
}
// Load each line into a StylesheetDatalet
for (;;)
{
// Skip any lines beginning with # comment char or that are blank
if ((!line.startsWith(QETEST_COMMENT_CHAR)) && (line.length() > 0))
{
// Create a Datalet and initialize with the line's
// contents and default properties
StylesheetDatalet d = new StylesheetDatalet(line, defaults);
// Also pass over the global runId, if set
d.options.put("runId", defaults.getProperty("runId"));
//@todo Avoid spurious passes when output & gold not specified
// needs to detect when StylesheetDatalet doesn't
// properly have outputName and goldName set
// Add it to our vector
vec.addElement(d);
}
// Read next line and loop
try
{
line = br.readLine();
}
catch (IOException ioe2)
{
// Just force us out of the loop; if we've already
// read part of the file, fine
logger.logMsg(Logger.WARNINGMSG, "readQetestFileList: "
+ fileName + " threw: " + ioe2.toString());
break;
}
if (line == null)
break;
} // end of for (;;)
return vec;
}
/**
* Read in an xsltmark fileList specifying a list of files to test.
* <p>File format is an .ini file like so:</p>
* <pre>
* [avts]
* input=db100.xml
* stylesheet=avts.xsl
* output=avts.out
* reference=avts.ref
* iterations=100
* </pre>
* <p>Note that additional attributes will be logged as warnings
* and will be ignored.</p>
*
* @param logger to report problems to
* @param br BufferedReader to read from
* @param firstLine already read from br
* @param fileName String; name of the file
* @param desc to use of this file
* @param defaults default properties to potentially add to each datalet
* @return Vector of StylesheetDatalets, or null if error
*/
protected static Vector readXsltmarkFileList(Logger logger, BufferedReader br,
String firstLine, String fileName,
String desc, Properties defaults)
{
Vector vec = new Vector();
String line = firstLine;
// Parse each line and build a datalet
for (;;)
{
// If we're starting a section, parse the section to a datalet
if (line.startsWith(XSLTMARK_CHAR))
{
StylesheetDatalet d = readXsltmarkDatalet(logger, br, line, fileName, desc, defaults);
// Also pass over the global runId, if set
d.options.put("runId", defaults.getProperty("runId"));
// Add datalet to our vector
vec.addElement(d);
}
// Skip blank lines
else if (line.length() == 0)
{
/* no-op */
}
// Ooops, readXsltmarkDatalet didn't work right
else
{
logger.logMsg(Logger.WARNINGMSG, "readXsltmarkFileList parse error, unknown line: "
+ line);
}
// Read next line and loop
try
{
line = br.readLine();
}
catch (IOException ioe2)
{
// Just force us out of the loop; if we've already
// read part of the file, fine
logger.logMsg(Logger.WARNINGMSG, "readXsltmarkFileList: "
+ fileName + " threw: " + ioe2.toString());
break;
}
if (line == null)
break;
} // end of for (;;)
return vec;
}
/**
* Read in an xsltmark fileList specifying a list of files to test.
* <p>File format is an .ini file</p>
*
* @param logger to report problems to
* @param br BufferedReader to read from
* @param firstLine already read from br
* @param fileName String; name of the file
* @param desc to use of this file
* @param defaults default properties to potentially add to each datalet
* @return StylesheetDatalet with appropriate data, or null if error
*/
private static StylesheetDatalet readXsltmarkDatalet(Logger logger, BufferedReader br,
String firstLine, String fileName,
String desc, Properties defaults)
{
final String STYLESHEET_MARKER = "stylesheet=";
final String INPUT_MARKER = "input=";
final String OUTPUT_MARKER = "output=";
final String REFERENCE_MARKER = "reference=";
final String ITERATIONS_MARKER = "iterations=";
String line = firstLine;
StylesheetDatalet d = new StylesheetDatalet();
// Also pass over the default properties as well
d.options = new Properties(defaults);
// Parse lines throughout the section to build the datalet
for (;;)
{
// Each .ini file line starts with name of item to fill
if (line.startsWith(STYLESHEET_MARKER))
{
d.inputName = line.substring(STYLESHEET_MARKER.length());
}
else if (line.startsWith(INPUT_MARKER))
{
d.xmlName = line.substring(INPUT_MARKER.length());
}
else if (line.startsWith(OUTPUT_MARKER))
{
d.outputName = line.substring(OUTPUT_MARKER.length());
}
else if (line.startsWith(REFERENCE_MARKER))
{
d.goldName = line.substring(REFERENCE_MARKER.length());
}
else if (line.startsWith(XSLTMARK_CHAR))
{
d.setDescription(line);
}
else if (line.startsWith(ITERATIONS_MARKER))
{
d.options.put("iterations", line.substring(ITERATIONS_MARKER.length()));
}
else if (line.length() == 0)
{
// Blank lines mean end-of-section; return datalet
// This is the primary exit point for this method
return d;
}
else
{
logger.logMsg(Logger.WARNINGMSG, "readXsltmarkDatalet, unknown line: "
+ line);
}
// Read next line and loop
try
{
line = br.readLine();
}
catch (IOException ioe2)
{
// Just force us out of the loop; if we've already
// read part of the file, fine
logger.logMsg(Logger.WARNINGMSG, "readXsltmarkDatalet: "
+ fileName + " threw: " + ioe2.toString());
break;
}
if (line == null)
break;
} // end of for (;;)
logger.logMsg(Logger.ERRORMSG, "readXsltmarkDatalet: " + fileName
+ " no data found!");
return null;
}
}