--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.interop.update</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Update
+Bundle-SymbolicName: org.simantics.interop.update
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.interop.update.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.simantics.interop;bundle-version="1.0.0",
+ org.simantics.db;bundle-version="1.1.0",
+ org.simantics.db.common;bundle-version="1.1.0",
+ org.simantics.layer0;bundle-version="1.1.0",
+ org.simantics.issues;bundle-version="1.1.0",
+ org.simantics.issues.common;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.interop.update.model
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+package org.simantics.interop.update;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.simantics.interop.update"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
--- /dev/null
+package org.simantics.interop.update.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.ListUtils;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.interop.test.GraphChanges;
+import org.simantics.issues.common.IssueUtils;
+import org.simantics.issues.ontology.IssueResource;
+import org.simantics.layer0.Layer0;
+
+public abstract class AddDeleteUpdateOp extends UpdateOp {
+
+ protected boolean add;
+
+ public AddDeleteUpdateOp(GraphChanges changes) {
+ super(changes);
+ }
+
+ @Override
+ public boolean isAdd() {
+ return add;
+ }
+
+ @Override
+ public boolean isDelete() {
+ return !add;
+ }
+
+ @Override
+ public boolean requiresParentOps() {
+ return add;
+ }
+
+ @Override
+ public boolean requiresSubOps() {
+ return !add;
+ }
+
+ protected static void copyProperties(WriteGraph g, Resource source, Resource destination) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(g);
+ for (Statement s : g.getStatements(source, l0.HasProperty)) {
+ if (s.isAsserted(source))
+ continue;
+ Object value = g.getPossibleValue(s.getObject());
+ System.out.println(NameUtils.getSafeName(g, s.getSubject()) + " " + NameUtils.getSafeName(g, s.getPredicate()) + " " + NameUtils.getSafeName(g, s.getObject()) + " " + value);
+ if (value != null) {
+ Statement valueStm = g.getPossibleStatement(destination, s.getPredicate());
+ Resource valueResource = null;
+ if (valueStm != null && !valueStm.isAsserted(destination))
+ valueResource = valueStm.getObject();
+ if (valueResource == null) {
+ valueResource = g.newResource();
+ g.claim(valueResource, l0.InstanceOf, g.getSingleObject(s.getObject(), l0.InstanceOf));
+ g.claim(destination, s.getPredicate(), valueResource);
+ }
+ g.claimValue(valueResource, value);
+ //g.claimLiteral(destination, s.getPredicate(), value);
+ }
+ }
+ }
+
+ protected void copyIssues(WriteGraph g, Resource source, Resource destination) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(g);
+ IssueResource ir = IssueResource.getInstance(g);
+ Collection<Resource> issues = g.getObjects(source, ir.Issue_HasContext_Inverse);
+ for (Resource issue : issues) {
+ String label = g.getRelatedValue(issue, l0.HasLabel);
+ Resource severity = g.getSingleObject(issue, ir.Issue_HasSeverity);
+ List<Resource> sourceContexts = ListUtils.toList(g, g.getSingleObject(issue, ir.Issue_HasContexts));
+ List<Resource> destinationContext = new ArrayList<Resource>(sourceContexts.size());
+ // map context resources
+ for (Resource r : sourceContexts) {
+ if (r.equals(source))
+ destinationContext.add(destination);
+ else {
+ if (getChanges().getComparable().containsLeft(r))
+ destinationContext.add(getChanges().getComparable().getRight(r));
+ else
+ destinationContext.add(r);
+ }
+ }
+
+ IssueUtils.newUserIssue(g, label, severity, destinationContext);
+ }
+ }
+}
--- /dev/null
+package org.simantics.interop.update.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+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.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.layer0.Layer0;
+
+public abstract class UpdateNode {
+
+ public enum Status {EXIST,DELETED,NEW,CONTAINS};
+
+
+ private Status status;
+ private UpdateOp op;
+ private Resource r;
+
+
+ private Collection<UpdateNode> children = new ArrayList<UpdateNode>();
+ /**
+ *
+ * @param resource old Resource if status is DELETED or EXISTS.
+ * @param status
+ * @param changes
+ */
+ public UpdateNode(Status status, UpdateOp op) {
+
+ this.status = status;
+ this.op = op;
+ this.r = op.getResource();
+ }
+
+ public UpdateNode(Status status, Resource r) {
+
+ this.status = status;
+ this.op = null;
+ this.r = r;
+ }
+
+ public Resource getResource() {
+ return r;
+ }
+
+ public Resource getParentResource(ReadGraph g) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(g);
+ return g.getPossibleObject(r, l0.PartOf);
+ }
+
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public Collection<UpdateNode> getChildren() {
+ return children;
+ }
+
+ public void addChild(UpdateNode node) {
+ children.add(node);
+ }
+
+ public abstract ImageDescriptor getImage(ReadGraph graph) throws DatabaseException;
+
+ public String getLabel(ReadGraph graph) throws DatabaseException {
+ return getLabel(graph,r);
+ }
+
+ protected String getLabel(ReadGraph graph, Resource r) throws ValidationException, ServiceException, NoSingleResultException {
+ String label = NameUtils.getSafeLabel(graph, r);
+ if (label.length() == 0)
+ label = NameUtils.getSafeName(graph, r);
+
+ return label;
+ }
+
+
+ public UpdateOp getOp() {
+ return op;
+ }
+
+}
--- /dev/null
+package org.simantics.interop.update.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.interop.test.GraphChanges;
+
+/**
+ * Base class for update operations (adding and deleting objects)
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public abstract class UpdateOp {
+
+ private GraphChanges changes;
+
+ private boolean selected = false;
+ private boolean manualSelection = false;
+ protected boolean applied = false;
+
+ private Collection<UpdateOp> parentOps = new ArrayList<UpdateOp>();
+ private Collection<UpdateOp> subOps = new ArrayList<UpdateOp>();
+
+
+ public UpdateOp(GraphChanges changes) {
+ this.changes = changes;
+ }
+
+ public Collection<UpdateOp> getParentOps() {
+ return parentOps;
+ }
+
+ public Collection<UpdateOp> getSubOps() {
+ return subOps;
+ }
+
+ public void addParentOp(UpdateOp op) {
+ assert (!op.equals(this));
+ parentOps.add(op);
+ }
+
+ public void addSubOp(UpdateOp op) {
+ assert (!op.equals(this));
+ subOps.add(op);
+ }
+
+ public void removeParentOp(UpdateOp op) {
+ parentOps.remove(op);
+ }
+
+ public void removeSubOp(UpdateOp op) {
+ subOps.remove(op);
+ }
+
+ public GraphChanges getChanges() {
+ return changes;
+ }
+
+ public abstract boolean isAdd();
+ public abstract boolean isDelete();
+
+ public abstract boolean requiresParentOps();
+ public abstract boolean requiresSubOps();
+
+ public boolean select(boolean select) {
+ boolean b = _select(select);
+ if (b)
+ manualSelection = true;
+ return b;
+ }
+
+ private boolean _select(boolean select) {
+ if (select == selected)
+ return true;
+ if (select) {
+ if (requiresParentOps()) {
+ for (UpdateOp op : parentOps)
+ op._select(true);
+ }
+
+ selected = true;
+ manualSelection = false;
+ if (requiresSubOps()) {
+ for (UpdateOp op : subOps)
+ op._select(true);
+ }
+
+ } else {
+ selected = false;
+ manualSelection = false;
+ for (UpdateOp op : subOps) {
+ if (op.requiresParentOps())
+ op._select(false);
+ else if (!op.manualSelection)
+ op._select(false);
+ }
+ for (UpdateOp op : parentOps)
+ if (op.requiresSubOps())
+ op._select(false);
+ return true;
+ }
+ return false;
+ }
+ public boolean selected() {
+ return selected;
+ }
+
+ public boolean applied() {
+ return applied;
+ }
+ public void apply(WriteGraph g) throws DatabaseException {
+ if (applied)
+ return;
+ _apply(g);
+ applied = true;
+
+ }
+
+ protected abstract void _apply(WriteGraph g) throws DatabaseException;
+
+ /**
+ * Returns resource that this operation is changing.
+ * @return
+ */
+ public abstract Resource getResource();
+
+ /**
+ * Returns resource that this operation created during apply operation. If operation did not add anything, this returns null.
+ * @return
+ */
+ public abstract Resource getCreatedResource();
+
+}
--- /dev/null
+package org.simantics.interop.update.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.interop.test.GraphChanges;
+
+/**
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public abstract class UpdateOperations {
+
+ private List<UpdateOp> operations = new ArrayList<UpdateOp>();
+ private Map<Resource, UpdateOp> opMap = new HashMap<Resource, UpdateOp>();
+ private GraphChanges changes;
+
+ public UpdateOperations(GraphChanges changes) {
+ this.changes = changes;
+ }
+
+ public UpdateOp getUpdateOp(Resource r) {
+ return opMap.get(r);
+ }
+
+ public void applyAll(WriteGraph g) throws DatabaseException {
+ for (UpdateOp op : operations) {
+ apply(g, op);
+ }
+ }
+
+ public void applySelected(WriteGraph g) throws DatabaseException {
+ for (UpdateOp op : operations) {
+ if (op.selected())
+ apply(g, op);
+ }
+ }
+
+ public List<UpdateOp> getOperations() {
+ return operations;
+ }
+
+ public GraphChanges getChanges() {
+ return changes;
+ }
+
+ private void apply(WriteGraph g, UpdateOp op) throws DatabaseException {
+ Stack<UpdateOp> stack = new Stack<UpdateOp>();
+ _apply(g, stack, op);
+ }
+
+ private void _apply(WriteGraph g, Stack<UpdateOp> stack, UpdateOp op) throws DatabaseException {
+ if (op.applied())
+ return;
+ if (stack.contains(op))
+ return;
+ stack.push(op);
+ if (op.requiresParentOps()) {
+ for (UpdateOp pop : op.getParentOps())
+ if (!pop.applied())
+ _apply(g, stack, pop);
+ }
+ if (op.requiresSubOps()) {
+ for (UpdateOp sop : op.getSubOps())
+ if (!sop.applied())
+ _apply(g, stack, sop);
+ }
+ stack.pop();
+ op.apply(g);
+ }
+
+ protected List<UpdateOp> getOps() {
+ List<UpdateOp> list = new ArrayList<UpdateOp>(operations.size());
+ list.addAll(operations);
+ return list;
+ }
+
+ protected void addOp(Resource r, UpdateOp op) {
+ opMap.put(r, op);
+ operations.add(op);
+ }
+
+ protected void replaceOp(Resource r, UpdateOp op) {
+ UpdateOp oldOp = opMap.remove(r);
+ if (oldOp != null) {
+ operations.remove(oldOp);
+ }
+ opMap.put(r, op);
+ operations.add(op);
+ }
+
+ protected UpdateOp getOP(Resource r) {
+ return opMap.get(r);
+ }
+
+ public abstract void populate(ReadGraph g) throws DatabaseException;
+
+ protected boolean compares(Resource r1, Resource r2) {
+ if (r1.equals(r2))
+ return true;
+ if (changes.getComparable().contains(r1, r2))
+ return true;
+ return false;
+ }
+
+}
--- /dev/null
+package org.simantics.interop.update.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.interop.test.GraphChanges;
+import org.simantics.interop.update.model.UpdateNode.Status;
+
+
+public abstract class UpdateTree {
+
+ private UpdateNode rootNode;
+ private Map<Resource,UpdateNode> nodes;
+ private GraphChanges changes;
+ private UpdateOperations updateOps;
+
+
+ public UpdateTree(ReadGraph g, GraphChanges changes, UpdateOperations updateOps) throws DatabaseException {
+ this.changes = changes;
+ this.nodes = new HashMap<Resource, UpdateNode>();
+ this.rootNode = createNode(Status.EXIST, changes.getResource1());
+ nodes.put(changes.getResource1(), rootNode);
+ nodes.put(changes.getResource2(), rootNode);
+ this.updateOps = updateOps;
+ this.updateOps.populate(g);
+ populate(g);
+ }
+
+ public UpdateOperations getUpdateOps() {
+ return updateOps;
+ }
+
+ public UpdateNode getRootNode() {
+ return rootNode;
+ }
+
+ protected abstract UpdateNode createNode(Status status, Resource r);
+ protected abstract UpdateNode createNode(Status status, UpdateOp op);
+
+ private UpdateNode createNode(Resource r1, Resource r2) {
+ UpdateNode node = null;
+ if (r1 != null && r2 != null) {
+ node = createNode(Status.EXIST, r1);
+ nodes.put(r1, node);
+ nodes.put(r2, node);
+ } else if (r1 != null) {
+ node = createNode(Status.DELETED ,updateOps.getUpdateOp(r1));
+ nodes.put(r1, node);
+ } else if (r2 != null) {
+ node = createNode(Status.NEW, updateOps.getUpdateOp(r2));
+ nodes.put(r2, node);
+ }
+ return node;
+ }
+
+ public UpdateNode addNode(ReadGraph g, Resource r1, Resource r2) throws DatabaseException {
+ if (r1 != null && r2 != null) {
+ return null;
+ }
+ if (nodes.containsKey(r1))
+ return nodes.get(r1);
+ if (nodes.containsKey(r2))
+ return nodes.get(r2);
+
+ UpdateNode node = createNode(r1, r2);
+ connectParent(g,node);
+ return node;
+
+ }
+
+ protected boolean connectParent(ReadGraph g, UpdateNode node) throws DatabaseException {
+ UpdateNode parent = null;
+ while (true) {
+ Resource parentResource = node.getParentResource(g);
+ parent = nodes.get(parentResource);
+ if (parent == null) {
+ if (changes.getComparable().containsLeft(parentResource)) {
+ parent = createNode(parentResource, changes.getComparable().getRight(parentResource));
+ } else if (changes.getComparable().containsRight(parentResource)) {
+ parent = createNode(changes.getComparable().getLeft(parentResource) ,parentResource);
+ } else {
+ return false;
+ }
+ //parent.setStatus(Status.CONTAINS);
+ parent.addChild(node);
+ node = parent;
+ parent = null;
+ } else {
+ parent.addChild(node);
+ return true;
+ }
+
+ }
+ }
+
+ protected abstract boolean handleCustom(ReadGraph g, UpdateOp op) throws DatabaseException;
+
+ private void populate(ReadGraph g) throws DatabaseException{
+
+ for (UpdateOp op : updateOps.getOperations()) {
+ if (!handleCustom(g, op)) {
+ if (op.isAdd()) {
+ addNode(g, null,op.getResource());
+ } else {
+ addNode(g, op.getResource(), null);
+ }
+ }
+ }
+
+ }
+
+}