Added migration step implementation for changing InstanceOf statements 84/1384/5
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 15 Jan 2018 14:29:39 +0000 (16:29 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 15 Jan 2018 14:29:39 +0000 (16:29 +0200)
refs #7717

Change-Id: I0f427b5f222feae9b74d9e2d3d82becb0cda46af

bundles/org.simantics.db.layer0/adapters.xml
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/migration/InstanceOfMigrationStep.java [new file with mode: 0644]
bundles/org.simantics.layer0/graph/Layer0Migration.pgraph

index 5586b5fd1c8598e459b411d81310596ee54b1386..9e85e9a1bc15ab584f3522933b012ae60c468be2 100644 (file)
                        <graph />
                        <this />
                </type>         
+               <type uri = "http://www.simantics.org/Layer0-0.0/InstanceOfMigrationStep"
+                       class="org.simantics.db.layer0.migration.InstanceOfMigrationStep">
+                       <graph />
+                       <this />
+               </type>
        </target>
 
        <target interface="org.simantics.db.layer0.adapter.impl.ImportAdvisorFactory">
diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/migration/InstanceOfMigrationStep.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/migration/InstanceOfMigrationStep.java
new file mode 100644 (file)
index 0000000..26b051a
--- /dev/null
@@ -0,0 +1,142 @@
+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<Migration> ms = new ArrayList<>();
+        List<Resource> 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<Resource> 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<Resource> 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<Resource> 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<Resource> instancesOf(ReadGraph graph, Resource root, Resource type) throws DatabaseException {
+        return graph.syncRequest(
+                new QueryIndex(root, type, ""),
+                TransientCacheListener.<List<Resource>>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);
+    }
+
+}
\ No newline at end of file
index a2be43da621621ba2cc07cdb1876fe67450ef378..49361d515b5a2169eebaec9bbd9cd1f4b018074a 100644 (file)
@@ -55,3 +55,11 @@ L0.OrderedSetToListMigrationStep.Change <T L0.Entity
     >-- L0.OrderedSetToListMigrationStep.orderedSetType --> L0.String <T L0.HasProperty : L0.TotalFunction
     >-- L0.OrderedSetToListMigrationStep.listRelation --> L0.String <T L0.HasProperty : L0.TotalFunction
     >-- L0.OrderedSetToListMigrationStep.listType --> L0.String <T L0.HasProperty : L0.TotalFunction
+
+L0.InstanceOfMigrationStep <T L0.MigrationStep <T L0.List
+    L0.HasDescription """Simple migration step that switches one InstanceOf statement for another.
+Useful for cases where the type hierarchy in an ontology changes.
+The list is expected to contain an even number of URI string literals
+where the first literal specifies the type whose instances shall have
+their InstanceOf statements changed to the type pointed to by the second URI.
+The list can contain multiple of these pairs."""