From 2665fb66a324e6d08f28215a4734b95b001927f0 Mon Sep 17 00:00:00 2001 From: Marko Luukkainen Date: Mon, 20 Feb 2017 15:30:40 +0200 Subject: [PATCH] Base classes for model updates refs #7045 Change-Id: I9ac528fcec68f834d0229c14480b00635ad42e6b --- org.simantics.interop.update/.classpath | 7 + org.simantics.interop.update/.gitignore | 1 + org.simantics.interop.update/.project | 28 ++++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 18 +++ org.simantics.interop.update/build.properties | 4 + .../simantics/interop/update/Activator.java | 50 +++++++ .../update/model/AddDeleteUpdateOp.java | 93 ++++++++++++ .../interop/update/model/UpdateNode.java | 91 ++++++++++++ .../interop/update/model/UpdateOp.java | 137 ++++++++++++++++++ .../update/model/UpdateOperations.java | 112 ++++++++++++++ .../interop/update/model/UpdateTree.java | 115 +++++++++++++++ 12 files changed, 663 insertions(+) create mode 100644 org.simantics.interop.update/.classpath create mode 100644 org.simantics.interop.update/.gitignore create mode 100644 org.simantics.interop.update/.project create mode 100644 org.simantics.interop.update/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.simantics.interop.update/META-INF/MANIFEST.MF create mode 100644 org.simantics.interop.update/build.properties create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/Activator.java create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/model/AddDeleteUpdateOp.java create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateNode.java create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOp.java create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOperations.java create mode 100644 org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateTree.java diff --git a/org.simantics.interop.update/.classpath b/org.simantics.interop.update/.classpath new file mode 100644 index 0000000..eca7bdb --- /dev/null +++ b/org.simantics.interop.update/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.interop.update/.gitignore b/org.simantics.interop.update/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/org.simantics.interop.update/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/org.simantics.interop.update/.project b/org.simantics.interop.update/.project new file mode 100644 index 0000000..a0ac7df --- /dev/null +++ b/org.simantics.interop.update/.project @@ -0,0 +1,28 @@ + + + org.simantics.interop.update + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.interop.update/.settings/org.eclipse.jdt.core.prefs b/org.simantics.interop.update/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..0c68a61 --- /dev/null +++ b/org.simantics.interop.update/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +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 diff --git a/org.simantics.interop.update/META-INF/MANIFEST.MF b/org.simantics.interop.update/META-INF/MANIFEST.MF new file mode 100644 index 0000000..83657de --- /dev/null +++ b/org.simantics.interop.update/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +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 diff --git a/org.simantics.interop.update/build.properties b/org.simantics.interop.update/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.simantics.interop.update/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/Activator.java b/org.simantics.interop.update/src/org/simantics/interop/update/Activator.java new file mode 100644 index 0000000..ee2cf6f --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/Activator.java @@ -0,0 +1,50 @@ +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; + } + +} diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/AddDeleteUpdateOp.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/AddDeleteUpdateOp.java new file mode 100644 index 0000000..c01297e --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/AddDeleteUpdateOp.java @@ -0,0 +1,93 @@ +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 { + + 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 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 sourceContexts = ListUtils.toList(g, g.getSingleObject(issue, ir.Issue_HasContexts)); + List destinationContext = new ArrayList(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); + } + } +} diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateNode.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateNode.java new file mode 100644 index 0000000..e1312bf --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateNode.java @@ -0,0 +1,91 @@ +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 children = new ArrayList(); + /** + * + * @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 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; + } + +} diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOp.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOp.java new file mode 100644 index 0000000..907741c --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOp.java @@ -0,0 +1,137 @@ +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 + * + */ +public abstract class UpdateOp { + + private GraphChanges changes; + + private boolean selected = false; + private boolean manualSelection = false; + protected boolean applied = false; + + private Collection parentOps = new ArrayList(); + private Collection subOps = new ArrayList(); + + + public UpdateOp(GraphChanges changes) { + this.changes = changes; + } + + public Collection getParentOps() { + return parentOps; + } + + public Collection 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(); + +} diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOperations.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOperations.java new file mode 100644 index 0000000..a324763 --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOperations.java @@ -0,0 +1,112 @@ +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 + * + */ +public abstract class UpdateOperations { + + private List operations = new ArrayList(); + private Map opMap = new HashMap(); + 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 getOperations() { + return operations; + } + + private void apply(WriteGraph g, UpdateOp op) throws DatabaseException { + Stack stack = new Stack(); + _apply(g, stack, op); + } + + private void _apply(WriteGraph g, Stack 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 getOps() { + List list = new ArrayList(operations.size()); + list.addAll(operations); + return list; + } + + protected void addOp(Resource r, UpdateOp op) { + 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 static Statement getInverse(ReadGraph g, Statement otherComponentInv) throws DatabaseException{ + Statement otherComponent = null; + for (Statement s : g.getStatements(otherComponentInv.getObject(), g.getInverse(otherComponentInv.getPredicate()))) { + if (s.getObject().equals(otherComponentInv.getSubject())) + otherComponent = s; + } + return otherComponent; + } + + protected boolean compares(Resource r1, Resource r2) { + if (r1.equals(r2)) + return true; + if (changes.getComparable().contains(r1, r2)) + return true; + return false; + } + +} diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateTree.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateTree.java new file mode 100644 index 0000000..516ccd3 --- /dev/null +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateTree.java @@ -0,0 +1,115 @@ +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 nodes; + private GraphChanges changes; + private UpdateOperations updateOps; + + + public UpdateTree(ReadGraph g, GraphChanges changes, UpdateOperations updateOps) throws DatabaseException { + this.changes = changes; + this.nodes = new HashMap(); + 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 staus, Resource r); + protected abstract UpdateNode createNode(Status staus, 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; + + } + + private 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); + } + } + } + + } + +} -- 2.43.2