/*******************************************************************************
* Copyright (c) 2012-2015 INRIA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Generoso Pagano - initial API and implementation
******************************************************************************/
package fr.inria.soctrace.framesoc.core;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SimpleTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.inria.soctrace.framesoc.core.FramesocConstants.FramesocToolType;
import fr.inria.soctrace.framesoc.core.bus.FramesocBus;
import fr.inria.soctrace.framesoc.core.bus.FramesocBusTopic;
import fr.inria.soctrace.framesoc.core.tools.management.ExternalImporterExecutionManager;
import fr.inria.soctrace.framesoc.core.tools.management.ExternalToolExecutionManager;
import fr.inria.soctrace.framesoc.core.tools.management.ToolContributionManager;
import fr.inria.soctrace.framesoc.core.tools.model.IFramesocToolInput;
import fr.inria.soctrace.lib.model.AnalysisResult;
import fr.inria.soctrace.lib.model.Tool;
import fr.inria.soctrace.lib.model.Trace;
import fr.inria.soctrace.lib.model.TraceParam;
import fr.inria.soctrace.lib.model.TraceParamType;
import fr.inria.soctrace.lib.model.TraceType;
import fr.inria.soctrace.lib.model.utils.SoCTraceException;
import fr.inria.soctrace.lib.query.AnalysisResultQuery;
import fr.inria.soctrace.lib.query.ToolQuery;
import fr.inria.soctrace.lib.query.TraceParamTypeQuery;
import fr.inria.soctrace.lib.query.TraceQuery;
import fr.inria.soctrace.lib.query.TraceTypeQuery;
import fr.inria.soctrace.lib.query.conditions.ConditionsConstants.ComparisonOperation;
import fr.inria.soctrace.lib.query.conditions.SimpleCondition;
import fr.inria.soctrace.lib.storage.DBObject;
import fr.inria.soctrace.lib.storage.DBObject.DBMode;
import fr.inria.soctrace.lib.storage.SystemDBObject;
import fr.inria.soctrace.lib.storage.TraceDBObject;
import fr.inria.soctrace.lib.storage.utils.SQLConstants.FramesocTable;
import fr.inria.soctrace.lib.utils.Configuration;
import fr.inria.soctrace.lib.utils.Configuration.SoCTraceProperty;
import fr.inria.soctrace.lib.utils.IdManager;
/**
* Singleton to access management functionalities.
*
* @author "Generoso Pagano <generoso.pagano@inria.fr>"
*/
public final class FramesocManager {
/**
* Single instance of the manager
*/
private static FramesocManager instance = null;
/**
* Logger
*/
private static Logger logger = LoggerFactory.getLogger(FramesocManager.class);
/**
* Instance getter
*
* @return the manager instance
*/
public static FramesocManager getInstance() {
if (instance == null)
instance = new FramesocManager();
return instance;
}
/*
* Shortcuts
*/
private final String sysDbName = Configuration.getInstance().get(
SoCTraceProperty.soctrace_db_name);
/*
* Management methods
*/
/**
* Create the SoC-Trace System DB
*
* @throws SoCTraceException
* if the System DB already exists or if the check for its existence produces a DBMS
* dependent exception.
*/
public void createSystemDB() throws SoCTraceException {
if (isSystemDBExisting()) {
throw new SoCTraceException("System DB (" + sysDbName + ") already present");
}
new SystemDBObject(sysDbName, DBMode.DB_CREATE).close();
logger.debug("SystemDB created");
}
/**
* Register a new tool to the System DB. The System DB must exist.
*
* @param toolName
* tool name
* @param toolCommand
* tool command
* @param toolType
* tool type
* @param isPlugin
* boolean stating whether the tool is a plugin or not
* @param doc
* documentation text to be presented to the user
* @param extensionId
* tool extension id
* @throws SoCTraceException
*/
public void registerTool(String toolName, String toolCommand, String toolType,
boolean isPlugin, String doc, String extensionId) throws SoCTraceException {
if (toolName.equals("") || toolCommand.equals(""))
throw new SoCTraceException("Wrong parameters: ( '" + toolName + "', '" + toolCommand
+ "' )");
SystemDBObject db = getSystemDB();
int id = db.getNewId(FramesocTable.TOOL.toString(), "ID");
Tool tool = new Tool(id);
tool.setName(toolName);
tool.setCommand(toolCommand);
tool.setType(toolType);
tool.setPlugin(isPlugin);
tool.setDoc(doc);
tool.setExtensionId(extensionId);
db.save(tool);
db.commit();
db.close();
logger.debug("Tool " + tool.getName() + " registered");
}
/**
* Remove a tool from the system. If there are analysis results produced by this tool, they are
* removed too.
*
* @param tool
* the tool to remove
* @throws SoCTraceException
*/
public void removeTool(Tool tool) throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
// remove results
TraceQuery tq = new TraceQuery(sysDB);
List<Trace> traces = tq.getList();
for (Trace t : traces) {
TraceDBObject traceDB = null;
try {
traceDB = TraceDBObject.openNewInstance(t.getDbName());
AnalysisResultQuery arq = new AnalysisResultQuery(traceDB);
arq.setElementWhere(new SimpleCondition("TOOL_ID", ComparisonOperation.EQ,
String.valueOf(tool.getId())));
List<AnalysisResult> arl = arq.getList();
for (AnalysisResult ar : arl) {
traceDB.delete(ar);
}
} catch (SoCTraceException e) {
e.printStackTrace();
} finally {
DBObject.finalClose(traceDB);
}
}
// remove the tool
sysDB.delete(tool);
} finally {
DBObject.finalClose(sysDB);
}
}
/**
* Launch a tool as if using a simple command line interface: $ toolCommand arg1 arg2 ...
*
* @param tool
* tool to launch
* @param args
* arguments
* @throws SoCTraceException
*/
public void launchTool(Tool tool, IFramesocToolInput input) throws SoCTraceException {
// plugin tools
if (tool.isPlugin()) {
logger.debug("Launching plugin " + tool.getName());
ToolContributionManager.executePluginTool(tool, input);
return;
}
// external tools
if (tool.getType().equals(FramesocToolType.IMPORT.toString()))
new ExternalImporterExecutionManager(tool.getName(), input.getCommand()).execute();
else
new ExternalToolExecutionManager(tool.getName(), input.getCommand()).execute();
}
/**
* Remove the trace from the system, removing its metadata from the SystemDB and erasing the
* TraceDB.
*
* @param trace
* trace to remove
* @throws SoCTraceException
*/
public void deleteTrace(Trace trace) throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
// check if last trace of this type
TraceQuery tq = new TraceQuery(sysDB);
tq.setElementWhere(new SimpleCondition("TRACE_TYPE_ID", ComparisonOperation.EQ, String
.valueOf(trace.getType().getId())));
List<Trace> tl = tq.getList();
if (tl.size() == 1) {
sysDB.delete(trace.getType());
for (TraceParamType tpt : trace.getType().getTraceParamTypes()) {
sysDB.delete(tpt);
}
}
tq.clear();
sysDB.delete(trace);
for (TraceParam tp : trace.getParams()) {
sysDB.delete(tp);
}
sysDB.close();
// Check if the trace was already deleted on disk or in the DB ?
if (DBObject.isDBExisting(trace.getDbName())) {
// delete the trace db
TraceDBObject traceDB = TraceDBObject.openNewInstance(trace
.getDbName());
traceDB.dropDatabase();
}
// notify the bus
FramesocBus.getInstance().send(FramesocBusTopic.TOPIC_UI_SYNCH_TRACES_NEEDED, true);
logger.debug("Trace " + trace.getAlias() + " deleted");
} finally {
DBObject.finalClose(sysDB);
}
// delete the garbage after closing the connection with the system DB
// to have the DB up to date
deleteGarbageTraceType();
}
/**
* Create the Trace DB name with the predefined format: <BASE_NAME>_<yyyyMMdd_HHmmss_z>
*
* @param baseName
* the base name for the database
* @return The standard DB name, computed from a base name
*/
public String getTraceDBName(String baseName) {
// if empty string, use default name
if (baseName.equals("")) {
baseName = "TRACE_DB";
}
// remove space from name and replace with '_'
baseName = baseName.replaceAll("\\s+", "_");
// remove - from name and replace with '_'
baseName = baseName.replaceAll("-", "_");
// remove . from name and replace with '_'
baseName = baseName.replaceAll("\\.", "_");
// if first character is a digit, add a prefix
if (Character.isDigit(baseName.charAt(0)))
baseName = "DB_" + baseName;
// get current date
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(SimpleTimeZone.getDefault());
sdf.applyPattern("yyyyMMdd_HHmmss_z");
String date = sdf.format(new Date()).toString();
return baseName + "_" + date;
}
/*
* Convenience methods to check DB existence
*/
/**
* Check whether the System DB is existing or not.
*
* @return true if the System DB exists, false otherwise
* @throws SoCTraceException
*/
public boolean isSystemDBExisting() throws SoCTraceException {
return DBObject.isDBExisting(sysDbName);
}
/**
* Check whether the System DB are correct
*
* @return true if the settings are correct, false otherwise
* @throws SoCTraceException
*/
public boolean isSystemDBParameterCorrect() throws SoCTraceException {
return DBObject.checkSettings(sysDbName);
}
/**
* Get a new System DB object. WARNING: The client of this method MUST close the connection.
*
* @return the System DB object
* @throws SoCTraceException
* if the System DB does not exist or there is an error while checking its existence
* or creating it.
*/
public SystemDBObject getSystemDB() throws SoCTraceException {
if (!isSystemDBExisting()) {
throw new SoCTraceException("System DB (" + sysDbName + ") not existing");
}
return new SystemDBObject(sysDbName, DBMode.DB_OPEN);
}
/**
* Check whether a given DB is existing or not.
*
* @param dbName
* DB name
* @return true if the DB exists, false otherwise
* @throws SoCTraceException
*/
public boolean isDBExisting(String dbName) throws SoCTraceException {
return DBObject.isDBExisting(dbName);
}
/**
* Get the tool object from the DB given the tool name. If no tool is found, null is returned.
*
* @param name
* tool name
* @return the tool, or null if not found
* @throws SoCTraceException
*/
public Tool getTool(String name) throws SoCTraceException {
SystemDBObject sysDB = getSystemDB();
ToolQuery tq = new ToolQuery(sysDB);
tq.setElementWhere(new SimpleCondition("NAME", ComparisonOperation.EQ, name));
List<Tool> tl = tq.getList();
Tool ret = null;
for (Tool t : tl) {
ret = t;
break;
}
sysDB.close();
return ret;
}
/*
* Private methods
*/
/**
* Private constructor. Prevents instantiation.
*/
private FramesocManager() {
}
/**
* Add the new trace param to the passed traces.
*
* If the param type is not present, the type is created and saved along with the new param. If
* the param type is already present and there is no param for such type, the param is saved for
* that type. If the param type is already present and there is already a param for such type,
* the new param is not saved.
*
* @param traces
* traces where the new param should be added
* @param name
* new param name
* @param type
* new param type name
* @param value
* new param value
* @throws SoCTraceException
*/
public void saveParam(List<Trace> traces, String name, String type, String value)
throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
// trace type id -> (trace param type name -> trace param type)
Map<Integer, Map<String, TraceParamType>> typeMap = new HashMap<>();
// init all trace types
TraceTypeQuery ttQuery = new TraceTypeQuery(sysDB);
List<TraceType> ttList = ttQuery.getList();
for (TraceType tt : ttList) {
typeMap.put(tt.getId(), new HashMap<String, TraceParamType>());
}
// init all trace param types
TraceParamTypeQuery query = new TraceParamTypeQuery(sysDB);
List<TraceParamType> types = query.getList();
for (TraceParamType tpt : types) {
typeMap.get(tpt.getTraceType().getId()).put(tpt.getName(), tpt);
}
IdManager tptId = new IdManager();
IdManager tpId = new IdManager();
tptId.setNextId(1 + sysDB.getMaxId(FramesocTable.TRACE_PARAM_TYPE.toString(), "ID"));
tpId.setNextId(1 + sysDB.getMaxId(FramesocTable.TRACE_PARAM.toString(), "ID"));
for (Trace t : traces) {
Map<String, TraceParamType> tptMap = typeMap.get(t.getType().getId());
if (!tptMap.containsKey(name)) {
// the trace param type is not present for this trace type: create it
TraceParamType tpt = new TraceParamType(tptId.getNextId());
tpt.setName(name);
tpt.setType(type);
tpt.setTraceType(t.getType());
tptMap.put(name, tpt);
sysDB.save(tpt);
}
if (!t.getParamMap().containsKey(name)) {
// the trace param is not present for this trace param type: create it
TraceParam tp = new TraceParam(tpId.getNextId());
tp.setTrace(t);
tp.setValue(value);
tp.setTraceParamType(tptMap.get(name));
sysDB.save(tp);
}
}
sysDB.close();
} finally {
DBObject.finalClose(sysDB);
}
}
/**
* Delete the trace params from the passed traces.
*
* @param traces
* traces where the params should be removed
* @param params
* params to remove
* @throws SoCTraceException
*/
public void deleteParams(List<Trace> traces, List<String> params) throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
for (Trace t : traces) {
Map<String, TraceParam> paramMap = t.getParamMap();
for (String p : params) {
if (paramMap.containsKey(p)) {
TraceParam tp = paramMap.get(p);
paramMap.remove(p);
t.getParams().remove(tp);
sysDB.delete(tp);
}
}
}
sysDB.close();
} finally {
DBObject.finalClose(sysDB);
}
// delete the garbage after closing the connection with the system DB
// to have the DB up to date
deleteGarbageTraceParamType();
};
/**
* Remove all trace type for which there is no corresponding trace
*
* @throws SoCTraceException
*/
private void deleteGarbageTraceType() throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
Statement stm = sysDB.getConnection().createStatement();
stm.execute("DELETE FROM " + FramesocTable.TRACE_TYPE.toString()
+ " WHERE ID NOT IN (SELECT DISTINCT TRACE_TYPE_ID FROM "
+ FramesocTable.TRACE.toString() + ")");
stm.close();
} catch (SQLException e) {
throw new SoCTraceException(e);
} finally {
DBObject.finalClose(sysDB);
}
}
/**
* Remove all trace param types for which there is no corresponding trace param.
*
* @throws SoCTraceException
*/
private void deleteGarbageTraceParamType() throws SoCTraceException {
SystemDBObject sysDB = null;
try {
sysDB = getSystemDB();
Statement stm = sysDB.getConnection().createStatement();
stm.execute("DELETE FROM " + FramesocTable.TRACE_PARAM_TYPE.toString()
+ " WHERE ID NOT IN (SELECT DISTINCT TRACE_PARAM_TYPE_ID FROM "
+ FramesocTable.TRACE_PARAM.toString() + ")");
stm.close();
} catch (SQLException e) {
throw new SoCTraceException(e);
} finally {
DBObject.finalClose(sysDB);
}
}
}