/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.charts; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.simantics.Simantics; import org.simantics.charts.editor.ChartData; import org.simantics.databoard.util.URIUtil; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.layer0.request.PossibleModel; import org.simantics.history.History; import org.simantics.history.HistoryException; import org.simantics.history.HistoryManager; import org.simantics.modeling.subscription.CollectSubscriptions; import org.simantics.modeling.subscription.ModelHistoryCollector; import org.simantics.project.IProject; import org.simantics.simulation.experiment.IDynamicExperiment; import org.simantics.utils.FileUtils; /** * This class contains utilities for initializing history collection and makes * trending of subscribed dynamic experiment data possible. * * @author Tuukka Lehtonen */ public class TrendSupport implements ITrendSupport { // Input private IDynamicExperiment experiment; private String workspaceDataDirectoryName; // Internals private ModelHistoryCollector historyCollector; private ChartData chartData; public TrendSupport(IDynamicExperiment experiment, String workspaceDataDirectoryName) { this.experiment = experiment; this.workspaceDataDirectoryName = workspaceDataDirectoryName; } public void initializeHistoryCollection(ReadGraph graph) throws DatabaseException { final IProject project = Simantics.peekProject(); if (project == null) return; try { File workarea = getExperimentDirectory(graph, experiment.getResource(), true, "result-" + experiment.getIdentifier()); final HistoryManager history = History.openFileHistory(workarea); historyCollector = ModelHistoryCollector.createCollector( experiment, history, Activator.getDefault().getLog(), () -> { CollectSubscriptions cs = new CollectSubscriptions(TrendSupport.this.experiment, 0.1); return cs; }, () -> { // Reset chart data every time subscriptions change // to make sure that trend editor react. if (chartData != null) Charts.resetChartEditorData(project, experiment.getModel(), chartData); }); historyCollector.initialize(graph, 0, true); // Initialize chart source to support trend viewing HistoryManager historyManager = History.openFileHistory(historyCollector.getWorkarea()); chartData = new ChartData(experiment.getModel(), null, experiment, experiment.getDatasource(), historyManager, historyCollector.getCollector()); Charts.resetChartEditorData(project, experiment.getModel(), chartData); } catch (IOException e) { throw new DatabaseException(e); } catch (HistoryException e) { throw new DatabaseException(e); } catch (InterruptedException e) { throw new DatabaseException(e); } } public void dispose() { if (historyCollector != null) { historyCollector.dispose(); historyCollector = null; } if (chartData != null) { final IProject project = Simantics.peekProject(); if (project != null) Charts.resetChartEditorData(project, experiment.getModel(), null); chartData = null; } } /** * @param g * @param experiment * @param ensureExistence * @param subdirs * @return * @throws DatabaseException * @throws IOException */ protected File getExperimentDirectory(ReadGraph g, Resource experiment, boolean ensureExistence, String... subdirs) throws DatabaseException, IOException { Resource model = g.syncRequest(new PossibleModel(experiment)); if (model == null) throw new ValidationException( "Experiment '" + NameUtils.getSafeName(g, experiment) + "' is not part of any model. Has the experiment been removed already? Database may also be corrupted?"); String[] dirs = new String[3 + subdirs.length]; dirs[0] = workspaceDataDirectoryName; dirs[1] = "model-" + model.getResourceId(); dirs[2] = "experiment-" + experiment.getResourceId(); System.arraycopy(subdirs, 0, dirs, 3, subdirs.length); File experimentPath = getWorkspacePath(false, dirs); if (ensureExistence) ensureDirectoryExistence(experimentPath); return experimentPath; } /** * @param dir the directory that needs to be created if it does not exist * @return the requested directory if created or deemed existing * @throws IOException if the requested directory cannot be created */ protected static File ensureDirectoryExistence(File dir) throws IOException { if (dir.exists() && !dir.isDirectory()) FileUtils.deleteAll(dir); dir.mkdirs(); if (!dir.exists() || !dir.isDirectory()) throw new FileNotFoundException("Could not create directory '" + dir + "'. Out of disk space?"); return dir; } /** * @param escapeNames true to run each path segment through * {@link URIUtil#encodeFilename(String)} * @param relativeSegments path segments to append to the workspace root * path * @return the designated path within the workspace */ protected static File getWorkspacePath(boolean escapeNames, String... relativeSegments) { IPath finalPath = Platform.getLocation(); for (int i = 0; i < relativeSegments.length; ++i) finalPath = finalPath.append(escapeNames ? URIUtil.encodeFilename(relativeSegments[i]) : relativeSegments[i]); return finalPath.toFile(); } @Override public void setChartData(ReadGraph graph) throws DatabaseException { } @Override public ChartData getChartData() { return chartData; } }