package org.simantics.backup.db; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.simantics.Simantics; import org.simantics.backup.Activator; import org.simantics.backup.BackupException; import org.simantics.backup.Backups; import org.simantics.backup.IBackupProvider; import org.simantics.backup.ontology.BackupResource; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.Instances; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; public class ModelledBackupProvider implements IBackupProvider { List modelledBackups = new ArrayList<>(); public ModelledBackupProvider() { // Should this be on the constructor or can there be dynamic ontologies? this.modelledBackups = getModelledBackups(); } @Override public void lock() throws BackupException { Backups.lock(modelledBackups); } @Override public Future backup(Path targetPath, int revision) throws BackupException { final List> backups = new ArrayList<>(); final List exceptions = new ArrayList<>(backups.size()); for (IBackupProvider modelledBackup : modelledBackups) { try { Future future = modelledBackup.backup(targetPath, revision); backups.add(future); } catch (BackupException e) { exceptions.add(e); } } FutureTask task = new FutureTask<>(new Callable() { @Override public BackupException call() throws Exception { for (Future f : backups) { try { Exception exception = f.get(); if (exception != null) exceptions.add(exception); } catch (InterruptedException | ExecutionException e) { exceptions.add(e); } } BackupException problem = null; // Throw BackupException if any of the backup operations failed. if (!exceptions.isEmpty()) { IStatus[] ss = exceptions.stream() .map(e -> new Status(IStatus.ERROR, Activator.BUNDLE_ID, e.getMessage(), e)) .toArray(IStatus[]::new); problem = new BackupException(new CoreException(new MultiStatus(Activator.BUNDLE_ID, 0, ss, "Backup operation(s) failed to complete.", null))); } return problem; } }); new Thread(task).run(); return task; } @Override public void unlock() throws BackupException { Backups.unlock(modelledBackups); } @Override public void restore(Path fromPath, int revision) throws BackupException { for (IBackupProvider modelledBackup : modelledBackups) { modelledBackup.restore(fromPath, revision); } } private List getModelledBackups() { List modelledProviders = new ArrayList<>(0); try { modelledProviders = Simantics.getSession().syncRequest(new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { BackupResource BACKUP = BackupResource.getInstance(graph); Instances query = graph.adapt(BACKUP.ModelledBackupProvider, Instances.class); HashSet providers = new HashSet<>(); List ontologies = Layer0Utils.listOntologies(graph); for (Resource ontology : ontologies) { for(Resource provider : query.find(graph, ontology)) { providers.add(provider); } } List modelledBackups = new ArrayList<>(); for (Resource provider : providers) { Variable variable = Variables.getVariable(graph, provider); IBackupProvider modelledBackup = variable.getPropertyValue(graph, "instance"); modelledBackups.add(modelledBackup); } return modelledBackups; } }); } catch (DatabaseException e) { e.printStackTrace(); } return modelledProviders; } }