/******************************************************************************* * 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.tools.framesoc.exporter.dbimporter; import java.io.File; import java.io.FilenameFilter; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.io.FilenameUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.inria.soctrace.framesoc.core.FramesocManager; import fr.inria.soctrace.framesoc.core.tools.management.PluginImporterJob; import fr.inria.soctrace.framesoc.core.tools.model.FileInput; import fr.inria.soctrace.framesoc.core.tools.model.FramesocTool; import fr.inria.soctrace.framesoc.core.tools.model.IFramesocToolInput; import fr.inria.soctrace.framesoc.core.tools.model.IPluginToolJobBody; 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.storage.DBObject; import fr.inria.soctrace.lib.storage.SystemDBObject; import fr.inria.soctrace.lib.storage.TraceDBObject; import fr.inria.soctrace.lib.storage.dbmanager.DBManager; import fr.inria.soctrace.lib.storage.utils.SQLConstants.FramesocTable; import fr.inria.soctrace.lib.utils.IdManager; import fr.inria.soctrace.tools.framesoc.exporter.utils.ExportMetadata; import fr.inria.soctrace.tools.framesoc.exporter.utils.ExporterConstants; import fr.inria.soctrace.tools.framesoc.exporter.utils.Serializer; /** * * @author "Generoso Pagano <generoso.pagano@inria.fr>" */ public class FramesocDBImporter extends FramesocTool { private class TraceDBDescriptor { public String dbFile = ""; public String metaFile = ""; public TraceDBDescriptor(String dbFile) { this.dbFile = dbFile; } public boolean hasMeta() { return !metaFile.equals(""); } } private final static Logger logger = LoggerFactory.getLogger(FramesocDBImporter.class); /** * Plugin Tool Job body: we use a Job since we have to perform a long operation and we don't * want to freeze the UI. */ private class FramesocDBImporterJobBody implements IPluginToolJobBody { private FileInput input; // list of DB files public FramesocDBImporterJobBody(IFramesocToolInput input) { this.input = (FileInput) input; } private Trace prepareUnknownTrace(SystemDBObject sysDB) throws SoCTraceException { Trace t = new Trace(0); // the actual id is chosen at save time TraceType tt = new TraceType(0); // the actual id is chosen at save time tt.setName(ExporterConstants.UNKNOWN_TYPE_NAME); TraceType type = tt; t.setType(type); return t; } private void saveTrace(SystemDBObject sysDB, ExportMetadata metadata, int traceId) throws SoCTraceException { boolean isTypePresent = sysDB.isTraceTypePresent(metadata.trace.getType().getName()); // trace Trace t = new Trace(traceId); t.copyMetadata(metadata.trace); // type if (isTypePresent) { t.setType(sysDB.getTraceType(metadata.trace.getType().getName())); } else { TraceType tt = new TraceType(sysDB.getNewId(FramesocTable.TRACE_TYPE.toString(), "ID")); tt.setName(metadata.trace.getType().getName()); t.setType(tt); IdManager idm = new IdManager(); idm.setNextId(sysDB.getMaxId(FramesocTable.TRACE_PARAM_TYPE.toString(), "ID") + 1); for (TraceParamType tpt : metadata.trace.getType().getTraceParamTypes()) { TraceParamType ntpt = new TraceParamType(idm.getNextId()); ntpt.setTraceType(t.getType()); ntpt.setName(tpt.getName()); ntpt.setType(tpt.getType()); } } // trace param Map<String, TraceParam> tpm = metadata.trace.getParamMap(); IdManager idm = new IdManager(); idm.setNextId(sysDB.getMaxId(FramesocTable.TRACE_PARAM.toString(), "ID") + 1); for (TraceParamType tpt : t.getType().getTraceParamTypes()) { TraceParam tp = new TraceParam(idm.getNextId()); if (tpm.get(tpt.getName()) == null) { logger.debug("TraceParam for TraceParamType " + tpt.getName() + " not present"); continue; } tp.setTrace(t); tp.setTraceParamType(tpt); tp.setValue(tpm.get(tpt.getName()).getValue()); } // save and commit try { sysDB.save(t); for (TraceParam tp : t.getParams()) { sysDB.save(tp); } if (isTypePresent) return; sysDB.save(t.getType()); for (TraceParamType tpt : t.getType().getTraceParamTypes()) { sysDB.save(tpt); } } finally { sysDB.commit(); } } @Override public void run(IProgressMonitor monitor) throws SoCTraceException { SystemDBObject sysDB = null; try { // Open the System DB sysDB = SystemDBObject.openNewInstance(); IdManager idManager = new IdManager(); idManager.setNextId(sysDB.getMaxId(FramesocTable.TRACE.toString(), "ID") + 1); // For each DB file List<String> dbFiles = input.getFiles(); monitor.beginTask("Importing Framesoc databases", dbFiles.size()); for (String dbFile : dbFiles) { monitor.subTask("Importing " + dbFile); // get trace DB file and metadata file final TraceDBDescriptor des = getTraceDBDescriptor(dbFile); // prepare trace metadata ExportMetadata metadata = null; if (des.hasMeta()) { Serializer serializer = new Serializer(); metadata = serializer.deserialize(des.metaFile); } else { logger.debug("No *.meta file found. The trace will be imported with default metadata"); metadata = new ExportMetadata(); metadata.trace = prepareUnknownTrace(sysDB); } metadata.trace.setDbName(FramesocManager.getInstance().getTraceDBName( "FramesocDBImporter")); if (monitor.isCanceled()) return; // import the DB doImport(monitor, des, metadata); // manage analysis results manageResults(sysDB, metadata, des); // close and commit saveTrace(sysDB, metadata, idManager.getNextId()); monitor.worked(1); } } catch (SoCTraceException e) { feedback(false, e.toString()); if (sysDB != null) { sysDB.rollback(); sysDB.close(); } } finally { DBObject.finalClose(sysDB); } } private void doImport(IProgressMonitor monitor, TraceDBDescriptor des, ExportMetadata metadata) { // import trace as is, considering the DB name final DBManager dbm = DBManager.getDBManager(metadata.trace.getDbName()); final String dbName = des.dbFile; // import thread Thread th = new Thread() { @Override public void run() { logger.debug("thread body"); try { try { dbm.importDB(dbName); logger.debug("import done"); } catch (Exception e) { logger.debug("dropping DB"); dbm.dropDB(); logger.debug("DB dropped"); } } catch (SoCTraceException e) { e.printStackTrace(); } } }; th.start(); // watch dog while (th.isAlive()) { try { Thread.sleep(1000); } catch (InterruptedException ie) { logger.debug("interrupted exception in main thread"); th.interrupt(); return; } if (monitor.isCanceled()) { logger.debug("user pressed cancel"); logger.debug("interrupting thread"); th.interrupt(); return; } } } private void feedback(final boolean ok, final String s) { Display.getDefault().syncExec(new Runnable() { @Override public void run() { if (ok) MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "Importer", "Databases correctly imported.\n" + s); else MessageDialog.openError(Display.getCurrent().getActiveShell(), "Importer", "Error while importing.\n" + s); } }); } private Map<Integer, Integer> getOldToolIdMapping(TraceDBObject traceDB) throws SoCTraceException { Map<Integer, Integer> map = new HashMap<Integer, Integer>(); try { Statement stm = traceDB.getConnection().createStatement(); ResultSet rs = stm.executeQuery("SELECT ID, TOOL_ID FROM " + FramesocTable.ANALYSIS_RESULT); while (rs.next()) { map.put(rs.getInt(1), rs.getInt(2)); } stm.close(); } catch (SQLException e) { e.printStackTrace(); } return map; } private void manageResults(SystemDBObject sysDB, ExportMetadata metadata, TraceDBDescriptor des) throws SoCTraceException { TraceDBObject traceDB = null; try { traceDB = TraceDBObject.openNewInstance(metadata.trace.getDbName()); AnalysisResultQuery arq = new AnalysisResultQuery(traceDB); List<AnalysisResult> arl = arq.getList(); if (arl.size() > 0) { // there are results if (!des.hasMeta() || metadata.tools == null) { // there are not metadata or no tool information, clean results for (AnalysisResult ar : arl) { traceDB.delete(ar); } } else { // there are metadata and tool information // see if matching tools ToolQuery tq = new ToolQuery(sysDB); List<Tool> tl = tq.getList(); // tool name -> tool Map<String, Tool> name2tool = new HashMap<String, Tool>(); Map<Integer, Tool> id2tool = new HashMap<Integer, Tool>(); for (Tool t : tl) { name2tool.put(t.getName(), t); id2tool.put(t.getId(), t); } // old system tool id -> new system tool id Map<Integer, Integer> oldId2newId = new HashMap<Integer, Integer>(); final Set<Integer> arIdsToKeep = new HashSet<Integer>(); for (Tool t : metadata.tools) { if (name2tool.containsKey(t.getName())) { oldId2newId.put(t.getId(), name2tool.get(t.getName()).getId()); } } // analysis result with matching tool final List<AnalysisResult> arToShow = new LinkedList<AnalysisResult>(); Map<Integer, Integer> map = getOldToolIdMapping(traceDB); for (AnalysisResult ar : arl) { int oldToolId = map.get(ar.getId()); if (oldId2newId.containsKey(oldToolId)) { // update the tool to match the new system one ar.setTool(id2tool.get(oldId2newId.get(oldToolId))); arToShow.add(ar); } } // display user dialog if (arToShow.size() > 0) { Display.getDefault().syncExec(new Runnable() { @Override public void run() { IWorkbenchWindow window = PlatformUI.getWorkbench() .getActiveWorkbenchWindow(); ImportDBResultDialog dlg = new ImportDBResultDialog(window .getShell(), arToShow); dlg.open(); // there's only the Import button Object[] keep = dlg.getResultsToKeep(); // results to clean ids for (Object o : keep) { arIdsToKeep.add(((AnalysisResult) o).getId()); } } }); } for (AnalysisResult ar : arl) { if (!arIdsToKeep.contains(ar.getId())) traceDB.delete(ar); else traceDB.update(ar); } } } } finally { DBObject.finalClose(traceDB); } } private TraceDBDescriptor getTraceDBDescriptor(String dbFile) throws SoCTraceException { TraceDBDescriptor des = new TraceDBDescriptor(dbFile); // check that dbFile has been specified if (des.dbFile.equals("")) throw new SoCTraceException("No database file specified."); // check that dbFile exists final File db = new File(des.dbFile); if (!db.exists()) throw new SoCTraceException(dbFile + " not found."); // look for a matching meta file File[] metas = db.getParentFile().listFiles(new FilenameFilter() { public boolean accept(File dir, String filename) { return filename.equals(FilenameUtils.removeExtension(db.getName()) + ".meta"); } }); if (metas.length > 0) des.metaFile = metas[0].getAbsolutePath(); return des; } } @Override public void launch(IFramesocToolInput input) { PluginImporterJob job = new PluginImporterJob("Framesoc DB Importer", new FramesocDBImporterJobBody(input)); job.setUser(true); job.schedule(); } @Override public ParameterCheckStatus canLaunch(IFramesocToolInput input) { ParameterCheckStatus status = new ParameterCheckStatus(true, ""); List<String> files = ((FileInput) input).getFiles(); if (files.size() < 1) { status.message = "Specify one or more database file."; status.valid = false; return status; } for (String file : files) { File f = new File(file); if (!f.exists()) { status.valid = false; status.message = "The file " + file + " does not exist."; return status; } } return status; } }