package it.unina.seclab.jafimon;
import it.unina.seclab.jafimon.interfaces.IMonitor;
import it.unina.seclab.jafimon.util.SystemEnvironmentVariables;
import java.io.File;
import java.io.IOException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.Loader;
import javassist.NotFoundException;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.xml.sax.SAXException;
/**
* E' il componente principale nelle operazioni di monitoraggio e iniezione dei guasti.
* Questo componente viene lanciato prima di avviare il test del sistema target. Esso
* si occupa di caricare la configurazione che descrive le instrumentazioni da effettuare,
* istanzia opportunamente il {@link CustomTranslator} ed il parser per il file XML, ed
* infine si occupa di caricare la <i>main class</i> del sistema target, dando cos� il via
* alle operazioni di monitoraggio ed iniezione.
*
* @author Mauro Iorio
*
*/
public class Monitor implements IMonitor {
private static final Logger logger = Logger.getRootLogger();
/**
* La reference a questo <code>Monitor</code>
*/
private static Monitor theInstance = null;
/**
* Il javassist.Loader che si occupa del caricamento della main class
*/
private static URLLoader theLoader = null;
/**
* Il ClassPool da cui si caricano le classi
*/
private static ClassPool thePool = null;
/**
* Il CustomTranslator usato per manipolare le classi
*/
private static CustomTranslator theTranslator = null;
/**
* Il nome del file di configurazione
*/
private String cfgFile;
/**
* Crea l'istanza del <code>Monitor</code>
*
*/
protected static Monitor getGlobalInstance(URLLoader l, ClassPool p, Configuration cfg) throws NotFoundException, CannotCompileException {
logger.debug("getGlobalInstance");
if (theInstance == null) {
logger.debug("sto per istanziare il Monitor");
theInstance = new Monitor(l,p,cfg);
logger.debug("ho istanziato il Monitor");
}
logger.debug("getGlobalInstance ritorna");
return theInstance;
}
/**
* Restituisce la reference all'oggetto <code>Monitor</code>
* @return la reference all'oggetto <code>Monitor</code>
*/
public static Monitor getGlobalInstance() {
return theInstance;
}
/**
* Questo e' il punto di ingresso del <code>Monitor</code>. I <code>PhysicalAcivator</code>
* attivano il sistema da testare usando questa come main class. Quindi questo <code>Monitor</code>
* ha il compito di caricare il sistema vero e proprio. Per fare cio', args[1] viene inizializzato
* con il path completo del file di configurazione da usare, mentre args[0] viene inizializzato
* dal chiamante con il nome della main class del sistema da testare, infine i restanti
* args sono gli argomenti della linea di comando del sistema.
*
* @param args
* @throws Throwable se l'esecuzione del sistema genera eccezione
*/
public static void main(String args[]) throws Throwable {
try {
PropertyConfigurator.configure(SystemEnvironmentVariables.getEnvironmentVariable("JAFIMON_HOME") + "/log4j.properties");
} catch (IOException e) {
PropertyConfigurator.configure("log4j.properties");
}
logger.info("JaFiMon.Monitor started!");
logger.trace("CmdLine arguments:");
for (int i = 0; i < args.length; i++) {
logger.trace("\"" + args[i] + "\"");
}
thePool = ClassPool.getDefault();
thePool.importPackage("javassist");
thePool.importPackage("javassist.expr");
theLoader = new URLLoader(Monitor.class.getClassLoader(),thePool);
// Evito i conflitti per le classi Logging
theLoader.delegateLoadingOf("org.apache.commons.logging.");
theLoader.delegateLoadingOf("org.apache.log4j.");
theLoader.delegateLoadingOf("javassist.");
logger.trace("loader delegato");
if (! args[0].endsWith(".xml")) {
logger.fatal("Il primo parametro deve essere una configuration");
return;
}
Configuration cfg = new Configuration(args[0]);
logger.debug("Sto per caricare la cfg");
cfg.load(SystemEnvironmentVariables.getEnvironmentVariable("JAFIMON_HOME") + File.separator + "data" + File.separator + "configurations");
logger.debug("Ho caricato la cfg");
theInstance = Monitor.getGlobalInstance(theLoader,thePool,cfg);
// Preparo gli argomenti e la main class da lanciare
String[] pargs = new String[args.length - 2];
System.arraycopy(args, 2, pargs, 0, pargs.length);
logger.info("JaFiMon.Monitor starting System Under Test!");
logger.trace("Invoking " + args[1]);
for (int i = 0; i < pargs.length; i++) {
logger.trace("\"" + pargs[i] + "\"");
}
theLoader.run(args[1], pargs);
logger.info("JaFiMon.Monitor stopped!");
}
/**
* Istanzia un nuovo <code>Monitor</code>
*/
protected Monitor(URLLoader thaLoader, ClassPool thePool, Configuration cfg) throws NotFoundException, CannotCompileException {
// Se il costruttore viene chiamato con parametro nullo significa
// che qualcuno ha chiamato la getGlobalInstance passando null E
// non era ancora stata creata una istanza del Monitor. Questo e'
// sintomo di errore, quindi fermo tutto!
if (cfg == null) {
logger.fatal("Monitor.getGlobalInstance called for the first time with null parameter! FATAL ERROR!");
throw new CannotCompileException("Monitor.getGlobalInstance called for the first time with null parameter! FATAL ERROR!");
}
theLoader = thaLoader;
try {
cfgFile = SystemEnvironmentVariables.getEnvironmentVariable("JAFIMON_HOME") + File.separator + "data" + File.separator + "configurations" + File.separator + cfg.getName();
} catch (IOException e1) {
throw new CannotCompileException(cfgFile,e1);
}
// Ora effettuo il parsing della configurazione ed inizializzo
// gli oggetti necessari
theTranslator = new CustomTranslator();
SAXParser parser;
ConfigurationSAXParser ch = new ConfigurationSAXParser(theTranslator,thePool);
try {
parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(cfgFile, ch);
} catch (ParserConfigurationException e1) {
throw new CannotCompileException(cfgFile,e1);
} catch (SAXException e1) {
throw new CannotCompileException(cfgFile,e1);
} catch (FactoryConfigurationError e1) {
throw new CannotCompileException(cfgFile,e1);
} catch (IOException e) {
throw new CannotCompileException(cfgFile,e);
}
theLoader.addTranslator(thePool, theTranslator); // Chiama xlat.start()
}
public static Monitor getTheInstance() {
return theInstance;
}
public static Loader getTheLoader() {
return theLoader;
}
public static ClassPool getThePool() {
return thePool;
}
public static CustomTranslator getTheTranslator() {
return theTranslator;
}
}