/**
* Copyright (C) 2008-2010, Squale Project - http://www.squale.org
*
* This file is part of Squale.
*
* Squale is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* Squale is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squale. If not, see <http://www.gnu.org/licenses/>.
*/
package org.squale.squalix.tools.cobertura;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.squale.squalecommon.enterpriselayer.businessobject.result.cobertura.CoberturaProjectMetricsBO;
import org.squale.squalecommon.util.xml.XmlImport;
/**
* This class allows instantiation of objects which parse result files form Cobertura coverage analysis
*/
public class CoberturaParser
extends XmlImport
{
/**
* Logger of the Cobertura Parser
*/
private static final Log LOGGER = LogFactory.getLog( CoberturaParser.class );
/**
* Default constructor
*/
public CoberturaParser()
{
/* Calling the super one and passing in the LOGGER */
super( LOGGER );
}
/**
* Main parse method. Used to parse the passed in result file. If you're not familiar with digester please refer to
* <a href="http://commons.apache.org/digester">Digester main site</a> where you could find usage examples,
* developers guide and more.
*
* @param pFile the xml file to be parsed
* @return the result in an object of type {@link CoberturaResultold_TODELETE}
*/
public CoberturaProjectMetricsBO parse( File pFile )
{
/* Instance to store general results */
CoberturaProjectMetricsBO result = null;
/* Object to store errors */
StringBuffer errors = new StringBuffer();
/* Preparing processing of the Xml result file */
Digester digesterXMLconfigured = getConfiguredParser();
/* Calling the main parsing method */
result = (CoberturaProjectMetricsBO) executeParsing( digesterXMLconfigured, pFile, errors );
return result;
}
/**
* <p>
* This method instantiates a digester rules of which have been set thanks to an external xml configuration file.
* </p>
* <p>
* Please refer to the <a href="http://commons.apache.org/digester/">Digester documentation</a> for more
* information regarding Digester.
* </p>
*
* @return an instance of Digester configured with the specified XML configuration file. Could return null if an
* error occurs with the configuration file
*/
private Digester getConfiguredParser()
{
/* Instance of digester which will be returned */
Digester digester = null;
/* Creating a configured digester thanks to the xml configuration file */
digester = DigesterLoader.createDigester( getClass().getResource( "coberturaParserXmlRules.xml" ) );
/* Setting the validation to false */
digester.setValidating( false );
/* EntityResolver which sends an empty String to skip DTD validation of the Digester API */
digester.setEntityResolver( this.new CoberturaResolver() );
return digester;
}
/**
* Inner class which implements <code>{@link EntityResolver}</code> interface.
*/
private class CoberturaResolver
implements EntityResolver
{
/**
* <p>
* This resolveEntity method is used to specify a local DTD file as it is needed to parse the Cobertura XML
* result files.<br />
* <p/>
* <p>
* The <b>setValidating(false)</b> method call tells Digester to not validate the XML data. However, it does
* "not" tell the <b>underlying XML parser</b> to skip the DOCTYPE.
* </p>
* <p>
* We are following advices of the Digester Wiki FAQ that is to say providing our own EntityResolver method
* whose resolveEntity() method always returns an empty String. That way, the parser won't go traipsing around
* the network trying to find things that it can't.
* </p>
*
* @param publicId portable identifier that is essentially a key used to look up the real location of the
* corresponding resource
* @param systemId non-portable identifier usually a reference to a local file
* @return a new InputSource which is <b>null</b>
* @throws SAXException if a problem is encountered while reading the DTD
* @throws IOException if a problem occurs while trying to open the DTD
*/
public InputSource resolveEntity( String publicId, String systemId )
throws SAXException, IOException
{
InputSource is = new InputSource();
StringReader sr = new StringReader( "" );
is.setCharacterStream( sr );
return is;
}
}
/**
* <p>
* This method executes the parsing of the XML result file and closes the stream.
* </p>
*
* @param pConfigDigester the configured digester
* @param pFile the file that has to be parsed
* @param pErrors a StringBuffer intended to store errors
* @return an Object resulting form the parsing of pStream with pConfigDigester
*/
protected Object executeParsing( Digester pConfigDigester, File pFile, StringBuffer pErrors )
{
/* Object that will be returned */
Object obj = null;
/* If the passed in pStream parameter is not null */
if ( null != pFile )
{
try
{
/* Executes the parsing of the result file */
obj = pConfigDigester.parse( pFile );
}
catch ( IOException ioExcep )
{
/* Uses the handleException method of the superClass to append error to the StringBuffer and log it */
handleException( ioExcep, pErrors );
}
catch ( SAXException saxExcep )
{
/* Uses the handleException method of the superClass to append error to the StringBuffer and log it */
handleException( saxExcep, pErrors );
}
}
/* Returning the parsing result */
return obj;
}
}