/* SAAF: A static analyzer for APK files.
* Copyright (C) 2013 syssec.rub.de
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.rub.syssec.saaf.db.datasources;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Dataasource that provides XML reading and optional validation for subclasses.
* <br/>
* The class provides a default implementation of the getData
* method that tries to open the member <em>dataFile</em> and
* apply schema validation if a schema was given in <em>schemafile</em>.
*
* After opening (and optionally validating) the data-file the doParse-Method
* is called. Subclasses must implement this to actually build a dataset
* from the DOM.
* <br/>
* The code does <b>not</b> throw an exception if the schema is invalid
* but merely logs it.
*
* @author Tilman Bender <tilman.bender@rub.de>
*
* @param <T>
*/
public abstract class AbstractXMLDataSource<T> implements Datasource<T>{
/**
* The path to the XML file that should be read into a DOM and passed to <em>doParse</em>
*/
protected String dataFile;
/**
* The path to the XML-Schema file that should be used to validate <em>dataFile</em>
*/
protected String schemaFile;
protected Logger logger = Logger.getLogger(AbstractXMLDataSource.class);
public AbstractXMLDataSource() {
super();
}
@Override
public Set<T> getData() throws DataSourceException {
Set<T> patterns = new TreeSet<T>();
File patternFile = new File(this.dataFile);
File schemaFile = new File(this.schemaFile);
Document data;
try {
data = readXMLFile(patternFile);
if(schemaFile.exists() && schemaFile.canRead())
{
logger.debug("Validating additional configuration...");
Document schema = readXMLFile(schemaFile);
if(isValid(data, schema))
{
logger.debug("Additional configuration valid.");
}else
{
logger.warn("Configuration file invalid! This may cause errors down the line");
}
}else{
logger.warn("No XML-Schema was found at "+schemaFile+" invalid additional configuration will not be detected");
}
patterns = doParse(data);
} catch (InvalidXMLException e) {
logger.error("Problem reading additional configuration "
+ patternFile.getAbsolutePath(), e);
}
return patterns;
}
protected abstract Set<T> doParse(Document data);
private Document readXMLFile(File file) throws InvalidXMLException {
Document xmlFile;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
builder = factory.newDocumentBuilder();
xmlFile = builder.parse(file);
} catch (ParserConfigurationException e) {
throw new InvalidXMLException(e);
} catch (SAXException e) {
throw new InvalidXMLException(e);
} catch (IOException e) {
throw new InvalidXMLException(e);
}
return xmlFile;
}
private boolean isValid(Document xmlDocument, Document xmlSchema) {
boolean valid = false;
try {
DOMSource xmlSource = new DOMSource(xmlDocument);
DOMSource schemaSource = new DOMSource(xmlSchema);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaSource);
Validator validator = schema.newValidator();
validator.validate(xmlSource);
valid = true;
} catch (SAXException e) {
logger.warn("Validation error",e);
} catch (IOException e) {
// do nothing valid=false is failsafe default.
}
return valid;
}
/**
* @return the dataFile
*/
public String getDataFile() {
return dataFile;
}
/**
* @param dataFile the dataFile to set
*/
public void setDataFile(String filename) {
this.dataFile = filename;
}
/**
* @return the schemaFile
*/
public String getSchemaFile() {
return schemaFile;
}
/**
* @param schemaFile the schemaFile to set
*/
public void setSchemaFile(String schemaFile) {
this.schemaFile = schemaFile;
}
/**
* @return the logger
*/
public Logger getLogger() {
return logger;
}
/**
* @param logger the logger to set
*/
public void setLogger(Logger logger) {
this.logger = logger;
}
}