package hudson.plugins.testabilityexplorer.parser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.*;
import hudson.plugins.testabilityexplorer.report.costs.Statistic;
import hudson.plugins.testabilityexplorer.report.costs.CostSummary;
import hudson.plugins.testabilityexplorer.parser.selectors.ConverterSelector;
import hudson.plugins.testabilityexplorer.parser.converters.ElementConverter;
/**
* Parses and merges Testability Explorer XML reports.
*
* @author reik.schatz
*/
public class XmlStatisticsParser extends StatisticsParser
{
private ConverterSelector m_converterSelector = null;
public XmlStatisticsParser(ConverterSelector converterSelector)
{
m_converterSelector = converterSelector;
}
public Collection<Statistic> parse(File inFile)
{
Collection<Statistic> statistics = new ArrayList<Statistic>();
FileInputStream fileInputStream = null;
try
{
fileInputStream = new FileInputStream(inFile);
statistics = parse(fileInputStream);
}
catch (FileNotFoundException e)
{
String filePath = inFile != null ? inFile.getPath() : "";
throw new IllegalStateException("Unable to find input file (" + filePath + ").", e);
}
finally
{
IOUtils.closeQuietly(fileInputStream);
}
return statistics;
}
public Collection<Statistic> parse(InputStream inputStream)
{
Collection<Statistic> results = new ArrayList<Statistic>();
BufferedInputStream bufferedInputStream = null;
try
{
bufferedInputStream = new BufferedInputStream(inputStream);
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(bufferedInputStream, null);
CostSummary overallCost = processRootElement(xpp);
results.add(new Statistic(overallCost));
}
catch (IOException e)
{
throw new IllegalStateException("Unable to process report file.", e);
}
catch (XmlPullParserException e)
{
throw new IllegalStateException("Unable to parse report file.", e);
}
finally
{
IOUtils.closeQuietly(bufferedInputStream);
}
sortByCost(results);
return results;
}
private void sortByCost(Collection<Statistic> results)
{
for (Statistic result : results)
{
result.sort();
}
}
/**
* Creates a new {@link CostSummary} from the specified parser. The parser is expected to be at the root element.
*
* @param xpp an {@link XmlPullParser}
* @return CostSummary
* @throws IOException if the underlaying file or stream cannot be processed
* @throws XmlPullParserException if the underlaying xml cannot be parsed
*/
protected CostSummary processRootElement(XmlPullParser xpp) throws IOException, XmlPullParserException
{
CostSummary overallCost = null;
int eventType = xpp.getEventType();
do {
// we are only interested in xml elements
if(eventType == XmlPullParser.START_TAG) {
String elementName = xpp.getName();
ElementConverter converter = m_converterSelector.getConverter(elementName);
if (converter == null)
{
throw new IllegalStateException("The " + m_converterSelector.getClass().getSimpleName() + " was unable to return a ElementConverter for XML tag name: " + elementName);
}
if (overallCost == null)
{
overallCost = (CostSummary) converter.construct(xpp, null);
}
else
{
converter.construct(xpp, overallCost);
}
}
eventType = xpp.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
return overallCost;
}
}