package it.unina.seclab.jafimon;
import it.unina.seclab.jafimon.exceptions.GenericConfigurationParsingException;
import it.unina.seclab.jafimon.exceptions.GenericConfigurationTrasformException;
import it.unina.seclab.jafimon.exceptions.InvalidConfigurationFileException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
/**
* Questa classe viene utilizzata internamente dal framework per effettuare la
* validazione ed il caricamento del file XML che definisce la <code>Configuration</code>
* attualmente in uso
*
* @author Mauro Iorio
*
*/
public class ConfigurationParser {
private static final Logger logger = Logger.getRootLogger();
/**
* Definisce il nome dell'elemento radice della struttura XML
*/
private static final String XML_ROOT_ELEMENT_NAME = "jafimon_configuration";
/**
* Definisce il nome dell'attributo che identifica la versione
*/
private static final String XML_ROOT_ATTRIBUTE_VERSION_NAME = "version";
/**
* Definisce la massima versione supportata dall'implementazione attuale
*/
private static final double MAX_SUPPORTED_VERSION = 1.0;
/**
* Definisce il tag principale che inizializza il modulo di
* monitoriaggio nella struttura XML
*/
private static final String MONITOR_ELEMENT_NAME = "monitor";
/**
* Definisce il tag principale che inizializza il modulo di
* iniezione guasti nella struttura XML
*/
private static final String INJECTOR_ELEMENT_NAME = "injector";
/**
* Effettua la validazione ed il parsing del file di configurazione.
* Questo metodo � in realt� un wrapper su {@link #parseAndCheck(InputStream)}
*
* @param source la rappresentazione testuale del codice XML da usare
* @return la reference all'oggetto <code>org.w3c.dom.Document</code> che contiene
* l'albero XML
* @throws InvalidConfigurationFileException il codice XML non definisce un
* file di configurazione valido
* @throws GenericConfigurationParsingException il sottosistema di parsing
* XML non � correttamente configurato
*/
public static Document parse(String source) throws InvalidConfigurationFileException,
GenericConfigurationParsingException {
Document res = null;
ByteArrayInputStream bis = new ByteArrayInputStream(source.getBytes());
res = parseAndCheck(bis);
return res;
}
/**
* Effettua la validazione ed il parsing del file di configurazione
* Questo metodo � in realt� un wrapper su {@link #parseAndCheck(InputStream)}
*
* @param fileName il file contenente il codice XML da usare
* @return la reference all'oggetto <code>org.w3c.dom.Document</code> che contiene
* l'albero XML
* @throws InvalidConfigurationFileException il codice XML non definisce un
* file di configurazione valido
* @throws GenericConfigurationParsingException il sottosistema di parsing
* XML non � correttamente configurato
*/
public static Document parse(File fileName) throws InvalidConfigurationFileException,
GenericConfigurationParsingException {
Document res = null;
FileInputStream fis;
try {
fis = new FileInputStream(fileName);
res = parseAndCheck(fis);
} catch (FileNotFoundException e) {
throw new GenericConfigurationParsingException(e.getLocalizedMessage());
}
return res;
}
/**
* Effettua realmente la validazione ed il caricamento del file XML
*
* @param is lo stream da cui caricare il codice
* @return la reference all'oggetto <code>org.w3c.dom.Document</code> che contiene
* l'albero XML
* @throws InvalidConfigurationFileException il codice XML non definisce un
* file di configurazione valido
* @throws GenericConfigurationParsingException il sottosistema di parsing
* XML non � correttamente configurato
*/
private static Document parseAndCheck(InputStream is) throws InvalidConfigurationFileException,
GenericConfigurationParsingException {
Document res = null;
double cfgVer = 0.0;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
DocumentBuilder parser = factory.newDocumentBuilder();
res = parser.parse(is);
// Recupero il root element
Element root = res.getDocumentElement();
// Controllo che sia giusto
if (! root.getTagName().equalsIgnoreCase(XML_ROOT_ELEMENT_NAME)) {
logger.error("Root element is \"" + root.getTagName() + "\" should be \"" + XML_ROOT_ELEMENT_NAME + "\"");
res = null;
throw new InvalidConfigurationFileException("Root element is \"" + root.getTagName() + "\" should be \"" + XML_ROOT_ELEMENT_NAME + "\"");
}
// Controllo la versione
try {
cfgVer = Double.parseDouble(root.getAttribute(XML_ROOT_ATTRIBUTE_VERSION_NAME));
if (cfgVer > MAX_SUPPORTED_VERSION) {
res = null;
logger.error("Configuration version is not supported. Max supported version is " + MAX_SUPPORTED_VERSION + ". Found " + cfgVer);
throw new InvalidConfigurationFileException("Configuration version is not supported. Max supported version is " + MAX_SUPPORTED_VERSION + ". Found " + cfgVer);
}
} catch (NumberFormatException nfe) {
logger.error("Attribute \"" + XML_ROOT_ATTRIBUTE_VERSION_NAME + "\" for root element has invalid value. Max supported version is " + MAX_SUPPORTED_VERSION);
res = null;
throw new InvalidConfigurationFileException("Attribute \"" + XML_ROOT_ATTRIBUTE_VERSION_NAME + "\" for root element has invalid value. Max supported version is " + MAX_SUPPORTED_VERSION);
}
// Verifico i nodi
if (root.getElementsByTagName(MONITOR_ELEMENT_NAME).getLength() <= 0) {
res = null;
logger.error("Configuration file is invalid. \"" + MONITOR_ELEMENT_NAME + "\" element not found");
throw new InvalidConfigurationFileException("Configuration file is invalid. \"" + MONITOR_ELEMENT_NAME + "\" element not found");
} else
logger.debug("Found \"" + MONITOR_ELEMENT_NAME + "\" element");
if (root.getElementsByTagName(INJECTOR_ELEMENT_NAME).getLength() <= 0) {
res = null;
logger.error("Configuration file is invalid. \"" + INJECTOR_ELEMENT_NAME + "\" element not found");
throw new InvalidConfigurationFileException("Configuration file is invalid. \"" + INJECTOR_ELEMENT_NAME + "\" element not found");
} else
logger.debug("Found \"" + INJECTOR_ELEMENT_NAME + "\" element");
} catch (ParserConfigurationException pce) {
logger.error("Could not locate a JAXP parser");
throw new GenericConfigurationParsingException("Could not locate a JAXP parser");
} catch (IOException e) {
logger.error("IOException occourred during parsing for \"" + is.toString() + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
throw new GenericConfigurationParsingException("IOException occourred during parsing for \"" + is.toString() + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
} catch (SAXException e) {
logger.error("XML document \"" + is.toString() + "\" is not well-formed");
throw new InvalidConfigurationFileException("XML document \"" + is.toString() + "\" is not well-formed");
}
return res;
}
/**
* Memorizza su disco una rappresentazione testuale dell'albero XML specificato
*
* @param doc l'albero XML da memorizzare
* @param fileName il nome del file su disco in cui memorizzare
* @throws GenericConfigurationTrasformException quando il framework non riesce
* a trasformare la rappresentazione XML della <code>Configuration</code>
* residente in memoria nell'equivalente rappresentazione testuale su file
*/
public static void save(Document doc, String fileName) throws GenericConfigurationTrasformException {
TransformerFactory xFrm = TransformerFactory.newInstance();
DOMSource source = new DOMSource(doc.getDocumentElement());
StreamResult result = new StreamResult(new File(fileName));
try {
xFrm.newTransformer().transform(source, result);
} catch (TransformerConfigurationException e) {
logger.error(e.getCause() + "occourred during saving for \"" + fileName + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
throw new GenericConfigurationTrasformException(e.getCause() + "occourred during saving for \"" + fileName + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
} catch (TransformerException e) {
logger.error(e.getCause() + "occourred during saving for \"" + fileName + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
throw new GenericConfigurationTrasformException(e.getCause() + "occourred during saving for \"" + fileName + "\" file. Message is: \"" + e.getLocalizedMessage() + "\"");
}
}
}