]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Support for linked lists in objmap2. 08/3108/1
authorReino Ruusu <reino.ruusu@semantum.fi>
Thu, 15 Aug 2019 12:35:18 +0000 (15:35 +0300)
committerReino Ruusu <reino.ruusu@semantum.fi>
Thu, 15 Aug 2019 12:35:18 +0000 (15:35 +0300)
gitlab #345

Change-Id: I7107ac75961602e74ed44b2c3d9867aefe7d29d8

bundles/org.simantics.objmap2/META-INF/MANIFEST.MF
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedList.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListAdd.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListGet.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListRem.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory2.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/LinkedListAccessor.java [new file with mode: 0644]
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java
bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java

index db84bf0c590ba30cc6a203dc614ddb4f151d07d8..55a1393f523e791ef1d8174e171554b4fcf0cffb 100644 (file)
@@ -10,7 +10,8 @@ Require-Bundle: org.simantics.db;bundle-version="1.1.0",
  org.simantics.layer0;bundle-version="1.0.0",
  org.simantics.db.common;bundle-version="1.1.0",
  org.simantics.structural.ontology;bundle-version="1.1.0",
- org.slf4j.api
+ org.slf4j.api,
+ org.simantics.db.layer0
 Export-Package: org.simantics.objmap.backward,
  org.simantics.objmap.bidirectional,
  org.simantics.objmap.exceptions,
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedList.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedList.java
new file mode 100644 (file)
index 0000000..7018a39
--- /dev/null
@@ -0,0 +1,40 @@
+package org.simantics.objmap.graph.annotations;
+
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.simantics.layer0.Layer0;
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;
+
+/**
+ * This field is a java.util.List or an array type that represents the contents
+ * of a Layer0.List entity that is the single object of the given relation. 
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@IsFieldRule
+public @interface LinkedList {
+       /**
+        * URI of a relation that has a Layer0.List as its object.
+        */
+       String value();
+       /**
+        * URI of the type of the list resource to create. 
+        */
+       String type() default Layer0.URIs.List;
+       boolean composition() default false;
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListAdd.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListAdd.java
new file mode 100644 (file)
index 0000000..197579f
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An add method add(int index, T value) for a linked list mapped to the single object
+ * of a given relation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface LinkedListAdd {
+       String value();
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListGet.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListGet.java
new file mode 100644 (file)
index 0000000..a474499
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.simantics.layer0.Layer0;
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;
+
+/**
+ * A get method that returns the contents of a linked list mapped to the single object of
+ * a given relation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@IsCollectionRule
+@HasCollectionAdder(LinkedListAdd.class)
+@HasCollectionRemover(LinkedListRem.class)
+public @interface LinkedListGet {
+       String value();
+       String type() default Layer0.URIs.List;
+       boolean composition() default false;
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListRem.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListRem.java
new file mode 100644 (file)
index 0000000..afc834e
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Remove method for a list of objects represented by a Layer0.List as the
+ * single object of a given relation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface LinkedListRem {
+       String value();
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory.java
new file mode 100644 (file)
index 0000000..072a6a2
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.annotations.factories;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Collection;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.ResourceNotFoundException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;
+import org.simantics.objmap.graph.annotations.LinkedList;
+import org.simantics.objmap.graph.rules.MappedElementsRule;
+import org.simantics.objmap.graph.rules.domain.LinkedListAccessor;
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;
+import org.simantics.objmap.graph.rules.range.FieldAccessor;
+
+public class LinkedListRuleFactory<Range> implements IFieldRuleFactory<Resource, Range> {
+
+    @Override
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {
+        LinkedList annotation = (LinkedList)_annotation;
+        return new MappedElementsRule<Resource,Range>(
+                new LinkedListAccessor(g.getResource(annotation.value()), g.getResource(annotation.type()), annotation.composition()),
+                new FieldAccessor<Range,Collection<Range>>(field)
+            );
+    }
+
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory2.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory2.java
new file mode 100644 (file)
index 0000000..3ef69d9
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.annotations.factories;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;
+import org.simantics.objmap.graph.annotations.LinkedListAdd;
+import org.simantics.objmap.graph.annotations.LinkedListGet;
+import org.simantics.objmap.graph.annotations.LinkedListRem;
+import org.simantics.objmap.graph.rules.MappedElementsRule;
+import org.simantics.objmap.graph.rules.domain.LinkedListAccessor;
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;
+import org.simantics.objmap.graph.rules.range.CollectionAccessor;
+
+public class LinkedListRuleFactory2<Range> implements ICollectionRuleFactory<Resource,Range> {
+       
+       @Override
+       public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation annotation,
+                       Method getter, Method adder, Method remover)
+                       throws DatabaseException {
+               LinkedListGet getterAnn = (LinkedListGet)annotation;
+               return new MappedElementsRule<Resource,Range>(new LinkedListAccessor(g.getResource(getterAnn.value()), g.getResource(getterAnn.type()), getterAnn.composition()),
+                                       new CollectionAccessor<Range,Range>(getter, adder, remover));
+       }
+       
+       @Override
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {
+               LinkedListGet getterAnn = (LinkedListGet)getterAnnotation;
+               LinkedListAdd adderAnn = (LinkedListAdd)annotation;
+               return getterAnn.value().equals(adderAnn.value());
+       }
+       
+       @Override
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {
+               LinkedListGet getterAnn = (LinkedListGet)getterAnnotation;
+               LinkedListRem adderAnn = (LinkedListRem)annotation;
+               return getterAnn.value().equals(adderAnn.value());
+       }
+
+}
diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/LinkedListAccessor.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/LinkedListAccessor.java
new file mode 100644 (file)
index 0000000..efdaab5
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Semantum oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.objmap.graph.rules.domain;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.ListUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.objmap.exceptions.MappingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Accesses the set of objects attached to the element by the given relation.
+ * @author Hannu Niemist√∂
+ */
+public class LinkedListAccessor implements IDomainAccessor<Resource,Collection<Resource>> {
+
+       static Logger LOGGER = LoggerFactory.getLogger(LinkedListAccessor.class);
+
+       Resource relation;
+       Resource listType;
+       boolean deleteExtraObjects;
+
+       public LinkedListAccessor(Resource relation, Resource listType, boolean deleteExtraObjects) {
+               super();
+               this.relation = relation;
+               this.listType = listType;
+               this.deleteExtraObjects = deleteExtraObjects;
+       }
+
+       @Override
+       public Collection<Resource> get(ReadGraph g, Resource element) throws MappingException {
+               try {
+                       LOGGER.info("        LinkdedListAccessor.get");
+                       return ListUtils.toList(g, g.getPossibleObject(element, relation));
+               } catch (DatabaseException e) {
+                       throw new MappingException(e);
+               }
+       }
+
+       @Override
+       public boolean set(WriteGraph g, Resource element, Collection<Resource> value)
+                       throws MappingException {
+               try {
+                       LOGGER.info("        LinkdedListAccessor.set");
+                       return MappingUtils.synchronizeList(g, element, relation, listType, new ArrayList<Resource>(value), deleteExtraObjects);
+               } catch (DatabaseException e) {
+                       throw new MappingException(e);
+               }
+
+       }
+
+}
index dbda44e34f837578692e70d2906b4bf304ed86ba..6f7f9260fde774cd50b59be3b95ae4f5a834425b 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2013, 2019 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,17 +8,24 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum oy - linked list utilities
  *******************************************************************************/
 package org.simantics.objmap.graph.rules.domain;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.simantics.db.Resource;
 import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.ListUtils;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.layer0.Layer0;
 
 /**
  * Static utility methods for rule implementations.
@@ -90,4 +97,75 @@ public class MappingUtils {
                return modified;
        }
 
+       public static boolean synchronizeList(WriteGraph g, Resource element, Resource relation, Resource listType, List<Resource> value, boolean deleteExtraObjects) throws DatabaseException {
+               final Layer0 L0 = Layer0.getInstance(g);
+               
+               // Return value
+               boolean modified = false;
+               
+               // Get the list - create a new one, if necessary
+               Resource currentList = g.getPossibleObject(element, relation);
+               if (currentList == null) {
+                       currentList = ListUtils.create(g, listType);
+                       g.claim(element, relation, currentList);
+                       modified = true;
+               }
+
+               // Synchronize elements
+               List<Resource> currentNodes = ListUtils.getListNodes(g, currentList);
+               int i = 0, j = 0;
+               while (i < currentNodes.size()) {
+                       Resource node = currentNodes.get(i);
+                       Resource v = g.getSingleObject(node, L0.List_Element);
+                       if (j < value.size() && v.equals(value.get(j))) {
+                               i++;
+                               j++;
+                       }
+                       else if (value.indexOf(v) > j) {
+                               // Insert new element in the middle
+                               insertElementBefore(g, L0, node, value.get(j));
+                               modified = true;
+                               j++;
+                       }
+                       else {
+                               // Remove deleted element
+                               if (deleteExtraObjects) g.deny(v);
+                               removeNode(g, L0, node);
+                               modified = true;
+                               i++;
+                       }
+               }
+
+               // Add new elements at end
+               while (j < value.size()) {
+                       // Add tailing elements
+                       insertElementBefore(g, L0, currentList, value.get(j));
+                       modified = true;
+                       j++;
+               }
+               
+               return modified;
+       }
+
+       private static Resource insertElementBefore(WriteGraph g, final Layer0 L0, Resource node, final Resource val)
+                       throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
+               Resource prev = g.getSingleObject(node, L0.List_Previous);
+               g.deny(prev, L0.List_Next, L0.List_Previous, node);
+               
+               Resource newNode = g.newResource();
+               g.claim(newNode, L0.InstanceOf, L0.List_Entry);
+               g.claim(prev, L0.List_Next, L0.List_Previous, newNode);
+               g.claim(newNode, L0.List_Next, L0.List_Previous, node);
+               g.claim(newNode, L0.List_Element, val);
+               return newNode;
+       }
+
+       private static void removeNode(WriteGraph g, final Layer0 L0, Resource node)
+                       throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException {
+               Resource prev = g.getSingleObject(node, L0.List_Previous);
+               Resource next = g.getSingleObject(node, L0.List_Next);
+               g.claim(prev, L0.List_Next, L0.List_Previous, next);
+               g.deny(node);
+       }
+
 }
index 56aa5da205ed21fb0cde31f9e3fd325d18a0a7f3..cf2f3bf45065c5bee4951da094d67b8e94686767 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
+ * Copyright (c) 2012, 2013, 2019 Association for Decentralized Information Management in
  * Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,7 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum oy - linked list mapping API and implementation
  *******************************************************************************/
 package org.simantics.objmap.graph.schema;
 
@@ -27,6 +28,8 @@ import org.simantics.objmap.graph.annotations.GraphType;
 import org.simantics.objmap.graph.annotations.HasCollectionAdder;
 import org.simantics.objmap.graph.annotations.HasCollectionRemover;
 import org.simantics.objmap.graph.annotations.HasSetter;
+import org.simantics.objmap.graph.annotations.LinkedListGet;
+import org.simantics.objmap.graph.annotations.LinkedList;
 import org.simantics.objmap.graph.annotations.OptionalRelatedElements;
 import org.simantics.objmap.graph.annotations.OrderedElementsGet;
 import org.simantics.objmap.graph.annotations.OrderedSetType;
@@ -39,6 +42,8 @@ import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements;
 import org.simantics.objmap.graph.annotations.RelatedValue;
 import org.simantics.objmap.graph.annotations.UpdateMethod;
 import org.simantics.objmap.graph.annotations.factories.CompoundRelatedGetSetValueRuleFactory;
+import org.simantics.objmap.graph.annotations.factories.LinkedListRuleFactory;
+import org.simantics.objmap.graph.annotations.factories.LinkedListRuleFactory2;
 import org.simantics.objmap.graph.annotations.factories.OptionalRelatedElementsRuleFactory;
 import org.simantics.objmap.graph.annotations.factories.OrderedElementsRuleFactory;
 import org.simantics.objmap.graph.annotations.factories.RelatedElementRuleFactory;
@@ -240,6 +245,8 @@ public class MappingSchemas {
             return new OptionalRelatedElementsRuleFactory<Object>();
         if (annotation.annotationType().equals(RelatedOrderedSetElements.class))
             return new RelatedOrderedSetElementsRuleFactory<Object>();
+        if (annotation.annotationType().equals(LinkedList.class))
+            return new LinkedListRuleFactory<Object>();
         return null;
     }
 
@@ -264,6 +271,8 @@ public class MappingSchemas {
             return new RelatedElementsRuleFactory2<Object>();
         if (annotation.annotationType().equals(OrderedElementsGet.class))
             return new OrderedElementsRuleFactory<Object>();
+        if (annotation.annotationType().equals(LinkedListGet.class))
+            return new LinkedListRuleFactory2<>();
         return null;
     }