public static HistorySamplerItem createHistorySamplerItem(ReadGraph graph, Resource subscriptionItem, ChartData data) throws DatabaseException {
try {
- Resource model = graph.syncRequest(new PossibleIndexRoot(subscriptionItem));
- if (model == null) {
- throw new DatabaseException("There is no model for " + subscriptionItem);
+ Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(subscriptionItem));
+ if (indexRoot == null) {
+ throw new DatabaseException("There is no index root for " + subscriptionItem);
}
ItemManager im = new ItemManager(data.history.getItems());
*
* @author Tuukka Lehtonen
*/
-public class TrendSupport {
+public class TrendSupport implements ITrendSupport {
// Input
private IDynamicExperiment experiment;
return finalPath.toFile();
}
+ @Override
+ public void setChartData(ReadGraph graph) throws DatabaseException {
+ }
+
+ @Override
+ public ChartData getChartData() {
+ return chartData;
+ }
+
}
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
+import java.util.ArrayList;
import org.simantics.db.Resource;
import org.simantics.db.Session;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.common.utils.Logger;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.indexing.internal.IndexChangedWriter;
import org.simantics.db.layer0.adapter.GenericRelationIndex;
import org.simantics.db.layer0.genericrelation.IndexedRelations;
import org.simantics.db.layer0.internal.SimanticsInternal;
return;
if (DEBUG)
System.out.println("Marking all indexes dirty");
- getAllDirtyFile().createNewFile();
+ File allDirtyFile = getAllDirtyFile();
+ if (allDirtyFile.createNewFile()) {
+ FileUtils.syncFile(allDirtyFile);
+ }
}
public static void clearAllDirty() throws IOException {
File indexBase = getIndexBaseLocation();
if (!indexBase.exists() || !indexBase.isDirectory())
return;
- delete(getAllDirtyFile());
forEachIndexPath(new Procedure<File, IOException>() {
@Override
public void execute(File indexPath) throws IOException {
- delete(getChangedFile(indexPath));
+ getChangedFile(indexPath).delete();
}
});
- }
+ getAllDirtyFile().delete();
+ }
+
/**
* Internal to indexing, invoked by {@link IndexedRelationsImpl} which
* doesn't want to throw these exceptions forward. Just log it.
*
* @param indexPath
*/
- static void markIndexChanged(File indexPath) {
- if (!indexPath.exists())
- throw new IllegalArgumentException("index path " + indexPath + " does not exist");
- if (!indexPath.isDirectory())
- throw new IllegalArgumentException("index path " + indexPath + " is not a directory");
+ static void markIndexChanged(Session session, File indexPath) {
+ if (DEBUG)
+ System.out.println("Marking index dirty: " + indexPath);
try {
- if (DEBUG)
- System.out.println("Marking index dirty: " + indexPath);
- getChangedFile(indexPath).createNewFile();
+ File changedFile = getChangedFile(indexPath);
+ // Mark change only once per DB session.
+ if (getIndexChangedWriter(session).markDirty(changedFile)) {
+ if (indexPath.mkdirs()) {
+ if (changedFile.createNewFile()) {
+ FileUtils.syncFile(changedFile);
+ }
+ }
+ }
} catch (IOException e) {
Logger.defaultLogError(e);
}
}
+ private static IndexChangedWriter getIndexChangedWriter(Session session) {
+ IndexChangedWriter writer = session.peekService(IndexChangedWriter.class);
+ if (writer == null) {
+ synchronized (IndexChangedWriter.class) {
+ if (writer == null)
+ session.registerService(IndexChangedWriter.class, writer = new IndexChangedWriter());
+ }
+ }
+ return writer;
+ }
+
public static void deleteAllIndexes() throws IOException {
File indexBase = DatabaseIndexing.getIndexBaseLocation();
- delete(indexBase);
+
+ ArrayList<String> filter = new ArrayList<>(2);
+ filter.add(getAllDirtyFile().getAbsolutePath());
+ filter.add(indexBase.getAbsolutePath());
+
+ FileUtils.deleteAllWithFilter(indexBase, filter);
+ FileUtils.deleteAll(indexBase);
}
public static void deleteIndex(final Resource relation, final Resource modelPart) throws DatabaseException {
public static void deleteIndex(File indexPath) throws IOException {
if (DEBUG)
System.out.println("Deleting index " + indexPath);
- delete(indexPath);
+
+ ArrayList<String> filter = new ArrayList<>(2);
+ filter.add(getChangedFile(indexPath).getAbsolutePath());
+ filter.add(indexPath.getAbsolutePath());
+
+ FileUtils.deleteAllWithFilter(indexPath, filter);
+ FileUtils.deleteAll(indexPath);
}
public static void validateIndexes() throws IOException {
// Make sure that index-base is a valid directory
if (DEBUG)
System.out.println(indexBase + " is not a directory! Removing it.");
- delete(indexBase);
+ FileUtils.deleteAll(indexBase);
indexBase.mkdirs();
return;
}
if (allDirtyFile.isFile()) {
if (DEBUG)
System.out.println("All indexes marked dirty, removing them.");
- delete(allDirtyFile);
deleteAllIndexes();
} else {
forEachIndexPath(new Procedure<File, IOException>() {
}
}
-
- private static void delete(File fileOrDir) throws IOException {
- if (fileOrDir.exists())
- FileUtils.deleteAll(fileOrDir);
- }
-
interface Procedure<T, E extends Throwable> {
void execute(T t) throws E;
}
try {
+ DatabaseIndexing.markIndexChanged(processor.getSession(), searcher.getIndexPath());
if(!searcher.startAccess(null, processor.getSession(), true)) {
// Could not write index for some reason. Ignore and let the next index query reinitialize the index.
return;
}
searcher.insertIndex(progress.newChild(40), relation, 1, documents);
- DatabaseIndexing.markIndexChanged(searcher.getIndexPath());
} catch (InvalidResourceReferenceException e) {
throw new IndexException(e);
LockHandle handle = lock(processor, Pair.make(relationResource, input), true);
try {
+ DatabaseIndexing.markIndexChanged(processor.getSession(), searcher.getIndexPath());
if(!searcher.startAccess(null, processor.getSession(), true)) {
// Could not write index for some reason. Ignore and let the next index query reinitialize the index.
return;
}
searcher.removeIndex(progress.newChild(40), relation, processor, key, keyValues);
- DatabaseIndexing.markIndexChanged(searcher.getIndexPath());
} catch (DatabaseException e) {
throw new IndexException(e);
try {
+ DatabaseIndexing.markIndexChanged(processor.getSession(), searcher.getIndexPath());
if(!searcher.startAccess(null, processor.getSession(), true)) {
// Could not write index for some reason. Ignore and let the next index query reinitialize the index.
return true;
}
- didChange = searcher.replaceIndex(progress.newChild(40), key, keyValues, relation, 1, documents);
- if(didChange)
- DatabaseIndexing.markIndexChanged(searcher.getIndexPath());
+ searcher.replaceIndex(progress.newChild(40), key, keyValues, relation, 1, documents);
} catch (InvalidResourceReferenceException e) {
throw new IndexException(e);
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.indexing.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An internal in-memory container for telling whether a certain index has been
+ * changed since the platform was last started up.
+ *
+ * @author Jussi Koskela
+ * @since 1.28.0
+ */
+public class IndexChangedWriter {
+ private Set<String> dirtyFiles = new HashSet<>();
+
+ public synchronized boolean markDirty(File dirtyFile) throws IOException {
+ return dirtyFiles.add(dirtyFile.getAbsolutePath());
+ }
+}
return null;
}
+ public static Resource getPossiblePredicateByLabel(ReadGraph graph, Resource instance, String predicateName) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ for(Resource type : graph.getPrincipalTypes(instance)) {
+ Map<String, Resource> domainOf = getDomainOf(graph, type);
+ for(Resource r : domainOf.values()) {
+ String label = graph.getPossibleRelatedValue(r, L0.HasLabel, Bindings.STRING);
+ if(predicateName.equals(label))
+ return r;
+ }
+ }
+ return null;
+ }
public static void claimLiteralDataboard(WriteGraph graph, Resource container, Resource property, String valueText) throws DatabaseException {
final boolean expanded = grp.getExpanded();
final boolean visible = grp.getVisible();
final boolean filterChanged = !objectEquals(filter, lastFilter);
+ final ISymbolGroup symbolGroup = (ISymbolGroup) grp.getData(SymbolLibraryKeys.KEY_GROUP);
+ final boolean filterMatchesGroup = filter != null && filter.select(viewer, null, symbolGroup);
// Find out how much data would be shown with the new filter.
- viewer.setFilter(filter);
+ viewer.setFilter(filterMatchesGroup ? null : filter);
Object[] elements = viewer.getFilteredElements();
- ISymbolGroup symbolGroup = (ISymbolGroup) grp.getData(SymbolLibraryKeys.KEY_GROUP);
- boolean filterMatchesGroup = filter != null && filter.select(viewer, null, symbolGroup);
boolean shouldBeVisible = !groupFiltered && (elements.length > 0 || filterMatchesGroup);
boolean shouldBeExpanded = shouldBeVisible && (filter != null || userExpanded);
-// System.out.format("%40s: visible/should be = %5s %5s, expanded/user expanded/should be = %5s %5s %5s\n",
+// System.out.format("%40s: filterMatchesGroup(%s) = %s, visible/should be = %5s %5s, expanded/user expanded/should be = %5s %5s %5s\n",
// grp.getText(),
+// symbolGroup.getName(),
+// String.valueOf(filterMatchesGroup),
// String.valueOf(visible),
// String.valueOf(shouldBeVisible),
// String.valueOf(expanded),
public synchronized static TDoubleArrayList sample( HistorySamplerItem item, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {
try {
- item.open();
+ // If there is something pending at this point, flush before opening for read
if(item.collector != null)
item.collector.flush();
+ item.open();
return sample(item.iter, from, end, timeWindow, timeStep, resample);
} finally {
item.close();
}
public static TDoubleArrayList sample( StreamIterator iter, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {
+ return sample(iter, from, end, timeWindow, timeStep, resample, 0.0);
+ }
+
+ public static TDoubleArrayList sample( StreamIterator iter, double from, double end, double timeWindow, double timeStep, boolean resample, Double sampleFrom ) throws HistoryException, IOException {
ExportInterpolation numberInterpolation = ExportInterpolation.LINEAR_INTERPOLATION;
- double startTime = 0.0;
+ double startTime = from;
+ if(sampleFrom != null) {
+ // This option can be used do define the offset of sampling. Samples will be sampleFrom + n * timeStep
+ startTime = sampleFrom;
+ }
TDoubleArrayList result = new TDoubleArrayList();
stepExperiment :: IExperiment -> Double -> <Proc> ()
simulateExperiment :: IExperiment -> Boolean -> <Proc> ()
disposeExperiment :: IExperiment -> <Proc> ()
- possibleActiveRunVariable ::Resource -> <ReadGraph> Variable
+ getExperimentState :: IExperiment -> <ReadGraph> ExperimentState
+ possibleActiveRunVariable ::Resource -> <ReadGraph> Maybe Variable
importJava "org.simantics.simulation.experiment.IExperiment" where
data IExperiment
+
+importJava "org.simantics.simulation.experiment.ExperimentState" where
+ data ExperimentState
+ INITIALIZING, RUNNING, STOPPED, DISPOSED :: ExperimentState
experimentFromRun :: Variable -> <ReadGraph> IExperiment
experimentFromRun run = (run#iExperiment) :: IExperiment
\ No newline at end of file
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
return false;
}
- private Collection<IProjectFeatureExtension> sortTopologically(Collection<IProjectFeatureExtension> toSort) {
- ArrayList<IProjectFeatureExtension> sorted = new ArrayList<IProjectFeatureExtension>(toSort);
- Collections.sort(sorted, new Comparator<IProjectFeatureExtension>() {
- Set<IProjectFeatureExtension> visited = new HashSet<IProjectFeatureExtension>();
- @Override
- public int compare(IProjectFeatureExtension e1, IProjectFeatureExtension e2) {
- visited.clear();
- if (deepRequires(visited, e1, e2))
- return 1;
- visited.clear();
- if (deepRequires(visited, e2, e1))
- return -1;
- return 0;
+ private void requiresDFS(IProjectFeatureExtension ext, ArrayList<IProjectFeatureExtension> result, Set<IProjectFeatureExtension> visited) {
+ if(visited.add(ext)) {
+ Set<IProjectFeatureExtension> reqs = required.getValues(ext);
+ if(reqs != null) {
+ for(IProjectFeatureExtension req : reqs) {
+ requiresDFS(req, result, visited);
+ }
}
- });
- return sorted;
+ result.add(ext);
+ }
+ }
+
+ private Collection<IProjectFeatureExtension> sortTopologically(Collection<IProjectFeatureExtension> toSort) {
+ ArrayList<IProjectFeatureExtension> result = new ArrayList<>();
+ Set<IProjectFeatureExtension> visited = new HashSet<>();
+ for(IProjectFeatureExtension ext : toSort) {
+ requiresDFS(ext, result, visited);
+ }
+ return result;
}
private Collection<IProjectFeatureExtension> requiredExtensions(IProjectFeatureExtension[] allExtensions, Collection<IProjectFeatureExtension> includedExtensions) throws ProjectException {
if (injectionTargetExt != null) {
changed = true;
includedProjectFeatureIds.add(ext.getId());
- result.add(ext);
+ if(!result.contains(ext))
+ result.add(ext);
required.add(injectionTargetExt, ext);
}
}
String description = StringUtils.safeString(el.getAttribute("description"));
boolean published = "true".equalsIgnoreCase(el.getAttribute("published"));
Collection<ProjectFeatureReference> requires = readProjectFeatureReferenceCollection(el, "requires");
- Collection<InjectedDependency> injections = readInjectedDependencies(el);
+ Collection<InjectedDependency> injections = readInjectedDependencies(el, id);
Collection<GroupReference> installGroups = readGroupReferenceCollection(el, "installGroup");
ProjectFeatureExtension ext = new ProjectFeatureExtension(el, id, label, description, published, requires, injections, installGroups);
this.extensions = newExtensions.toArray(new IProjectFeatureExtension[newExtensions.size()]);
}
- private Collection<InjectedDependency> readInjectedDependencies(IConfigurationElement element) {
+ private Collection<InjectedDependency> readInjectedDependencies(IConfigurationElement element, String id) {
Collection<InjectedDependency> result = new ArrayList<InjectedDependency>();
for (IConfigurationElement child : element.getChildren(INJECT_DEPENDENCY)) {
- String id = StringUtils.safeString(child.getAttribute("id"));
- if (id.isEmpty())
- // Invalid extension
- return null;
-
String targetId = StringUtils.safeString(child.getAttribute("targetId"));
if (targetId.isEmpty())
// Invalid extension
return null;
+
+ result.add(new InjectedDependency(new ProjectFeatureReference(id, false), new ProjectFeatureReference(targetId, false)));
+
}
return result;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.procedure.Listener;
+import org.simantics.db.request.ExternalRead;
import org.simantics.utils.datastructures.ListenerList;
public abstract class Experiment implements IExperiment {
@Override
public ExperimentState getState(ReadGraph graph) throws DatabaseException {
- throw new UnsupportedOperationException();
+ return graph.syncRequest(EXPERIMENT_STATE_READ);
}
public void changeState(ExperimentState newState) {
return identifier;
}
+ static class ExperimentStateRead implements ExternalRead<ExperimentState>, Runnable {
+
+ final private Experiment experiment;
+ private Listener<ExperimentState> listener = null;
+
+ ExperimentStateRead(Experiment experiment) {
+ this.experiment = experiment;
+ }
+
+ @Override
+ public void register(ReadGraph graph, final Listener<ExperimentState> procedure) {
+ //System.out.println("IcTrackerRequest.register: " + procedure);
+ listener = procedure;
+ procedure.execute(experiment.state);
+ }
+
+ @Override
+ public void unregistered() {
+ //System.out.println("IcTrackerRequest.unregister: " + listener);
+ listener = null;
+ }
+
+ @Override
+ public void run() {
+ Listener<ExperimentState> l = listener;
+ //System.out.println("IcTrackerRequest.run: " + l);
+ if (l != null)
+ l.execute(experiment.state);
+ }
+ }
+
+ private ExperimentStateRead EXPERIMENT_STATE_READ = new ExperimentStateRead(this);
+
}
((IDynamicExperiment)experiment).simulate(enabled);
}
+ public static ExperimentState getExperimentState(ReadGraph graph, IExperiment experiment) throws DatabaseException {
+ return experiment.getState(graph);
+ }
+
public static void disposeExperiment(final IExperiment experiment) {
if(experiment instanceof IDynamicExperiment) {
Export-Package: org.simantics.utils.threads,
org.simantics.utils.threads.logger
Bundle-Vendor: VTT Technical Research Centre of Finland
-Require-Bundle: org.eclipse.swt;bundle-version="3.6.0";resolution:=optional
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
- * 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.utils.threads;
-
-import java.util.concurrent.Executor;
-
-import org.eclipse.swt.widgets.Display;
-
-public class Executors2 {
-
- public static Executor createSWTExecutor(Display display, boolean async) {
- return async ? new SWTExecutorAsync(display) : new SWTExecutorSync(display);
- }
-
-}
-
-class SWTExecutorAsync implements Executor {
-
- Display display;
- public SWTExecutorAsync(Display display)
- {
- this.display = display;
- }
-
- @Override
- public void execute(Runnable command) {
- // Don't accept work if the SWT thread is disposed.
- if (display.isDisposed())
- throw new RuntimeException("The SWT thread has been disposed");
- display.asyncExec(command);
- }
-
-}
-
-class SWTExecutorSync implements Executor {
-
- Display display;
- public SWTExecutorSync(Display display)
- {
- this.display = display;
- }
-
- @Override
- public void execute(Runnable command) {
- // Don't accept work if the SWT thread is disposed.
- if (display.isDisposed())
- throw new RuntimeException("The SWT thread has been disposed");
- display.syncExec(command);
- }
-
-}
-
}
}
+ @FunctionalInterface
+ public static interface FileOperation {
+ IOperation<Boolean, IOException> perform(File file);
+
+ default void perform(File... files) {
+ for (File f : files)
+ perform(f);
+ }
+ }
+
+ public static class DeleteOperation implements FileOperation {
+ private final FileService service;
+ private final DeleteOption[] options;
+
+ public DeleteOperation(FileService service, DeleteOption... options) {
+ this.service = service;
+ this.options = options;
+ }
+
+ @Override
+ public IOperation<Boolean, IOException> perform(File file) {
+ return service.scheduleDeleteIfExists(file, options);
+ }
+ }
+
/**
* Schedules a file to be deleted at some point in the future when the
* system allows it to be deleted if ever.
*/
IOperation<Boolean, IOException> scheduleDeleteIfExists(File file, DeleteOption... options);
+ /**
+ * @param options
+ * the deletion options to be used by the returned FileOperation
+ * @return a FileOperation that runs
+ * {@link #scheduleDeleteIfExists(File, DeleteOption...)} for any
+ * files given to it
+ * @since 1.28.0
+ */
+ default FileOperation deleteOperation(DeleteOption... options) {
+ return new DeleteOperation(this, options);
+ }
+
}
return FileVisitResult.CONTINUE;
}
}
+
+ public static void syncFile(File file) throws IOException {
+ try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
+ raf.getFD().sync();
+ }
+ }
}