package org.simantics.db.layer0.migration; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.WriteGraph; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.DelayedWriteRequest; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.impl.EntityInstances.QueryIndex; import org.simantics.db.layer0.request.PossibleResource; import org.simantics.layer0.Layer0; /** * Changes L0.InstanceOf relations according to descriptions in the migrated * index root. * * @author Tuukka Lehtonen * @since 1.33.0 */ public class InstanceOfMigrationStep implements MigrationStep { private static class Migration { public final String fromUri; public final String toUri; public Migration(String from, String to) { this.fromUri = from; this.toUri = to; } @Override public String toString() { return fromUri + " -> " + toUri; } } private static class RMigration { public final Migration m; public final Resource from; public final Resource to; public RMigration(RequestProcessor processor, Migration m) throws DatabaseException { this.m = m; this.from = processor.syncRequest(new PossibleResource(m.fromUri)); this.to = processor.syncRequest(new PossibleResource(m.toUri)); } public boolean isValid() { return from != null && to != null; } } private final Migration[] migrations; public InstanceOfMigrationStep(String fromUri, String toUri) { this.migrations = new Migration[] { new Migration(fromUri, toUri) }; } public InstanceOfMigrationStep(ReadGraph graph, Resource step) throws DatabaseException { List ms = new ArrayList<>(); List uris = ListUtils.toList(graph, step); int size = uris.size() & ~1; for (int i = 0; i < size; i += 2) { String from = graph.getPossibleValue(uris.get(i), Bindings.STRING); String to = graph.getPossibleValue(uris.get(i+1), Bindings.STRING); if (from != null && to != null) ms.add(new Migration(from, to)); } migrations = ms.toArray(new Migration[ms.size()]); } @Override public void applyTo(final IProgressMonitor monitor, Session session, MigrationState state) throws DatabaseException { final Collection roots = state.getProperty(MigrationStateKeys.CURRENT_ROOT_RESOURCES); if (roots.isEmpty()) return; final PrintWriter log = MigrationUtils.getProperty(state, MigrationStateKeys.MESSAGE_LOG_WRITER, NullWriter.PRINT_INSTANCE); session.sync(new DelayedWriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { migrateInstances(monitor, graph, roots, log); } }); } private void migrateInstances(IProgressMonitor monitor, WriteGraph graph, Collection roots, PrintWriter log) throws DatabaseException { for (Migration m : migrations) migrateInstances(monitor, graph, new RMigration(graph, m), roots, log); } private void migrateInstances(IProgressMonitor monitor, WriteGraph graph, RMigration rm, Collection roots, PrintWriter log) throws DatabaseException { log.println("## InstanceOf Migration ##"); log.println("* From: `" + rm.m.fromUri + "`"); log.println("* To: `" + rm.m.toUri + "`"); if (rm.isValid()) { for (Resource root : roots) migrateInstances(monitor, graph, root, rm, log); } else { log.println("\nSkipping migration as invalid.\n"); } } private static void migrateInstances(IProgressMonitor monitor, WriteGraph graph, Resource root, RMigration migration, PrintWriter log) throws DatabaseException { log.println("### Migrating root `" + NameUtils.getSafeName(graph, root) + "` ###"); String rootUri = NameUtils.getURIOrSafeNameInternal(graph, root); Layer0 L0 = Layer0.getInstance(graph); for (Resource instance : instancesOf(graph, root, migration.from)) { if (graph.hasStatement(instance, L0.InstanceOf, migration.from)) { graph.deny(instance, L0.InstanceOf, null, migration.from); graph.claim(instance, L0.InstanceOf, null, migration.to); log.println("* `" + relativeUri(graph, rootUri, instance) + "`"); } } } private static List instancesOf(ReadGraph graph, Resource root, Resource type) throws DatabaseException { return graph.syncRequest( new QueryIndex(root, type, ""), TransientCacheListener.>instance()); } private static String relativeUri(ReadGraph graph, String rootUri, Resource r) throws DatabaseException { String uri = graph.getPossibleURI(r); return uri != null ? uri.substring(rootUri.length()) : NameUtils.getURIOrSafeNameInternal(graph, r); } }