From: Reino Ruusu Date: Thu, 15 Aug 2019 12:35:18 +0000 (+0300) Subject: Support for linked lists in objmap2. X-Git-Tag: v1.43.0~136^2~114 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=87d3c60a5c520cca584c54e6bc0fd8c9576141a7 Support for linked lists in objmap2. gitlab #345 Change-Id: I7107ac75961602e74ed44b2c3d9867aefe7d29d8 --- diff --git a/bundles/org.simantics.objmap2/META-INF/MANIFEST.MF b/bundles/org.simantics.objmap2/META-INF/MANIFEST.MF index db84bf0c5..55a1393f5 100644 --- a/bundles/org.simantics.objmap2/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.objmap2/META-INF/MANIFEST.MF @@ -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 index 000000000..7018a3915 --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedList.java @@ -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 index 000000000..197579f71 --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListAdd.java @@ -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 index 000000000..a4744994b --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListGet.java @@ -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 index 000000000..afc834ea8 --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/LinkedListRem.java @@ -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 index 000000000..072a6a2df --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory.java @@ -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 implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + LinkedList annotation = (LinkedList)_annotation; + return new MappedElementsRule( + new LinkedListAccessor(g.getResource(annotation.value()), g.getResource(annotation.type()), annotation.composition()), + new FieldAccessor>(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 index 000000000..3ef69d989 --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/LinkedListRuleFactory2.java @@ -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 implements ICollectionRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + LinkedListGet getterAnn = (LinkedListGet)annotation; + return new MappedElementsRule(new LinkedListAccessor(g.getResource(getterAnn.value()), g.getResource(getterAnn.type()), getterAnn.composition()), + new CollectionAccessor(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 index 000000000..efdaab56c --- /dev/null +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/LinkedListAccessor.java @@ -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> { + + 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 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 value) + throws MappingException { + try { + LOGGER.info(" LinkdedListAccessor.set"); + return MappingUtils.synchronizeList(g, element, relation, listType, new ArrayList(value), deleteExtraObjects); + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + +} diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java index dbda44e34..6f7f9260f 100644 --- a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java @@ -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 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 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); + } + } diff --git a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java index 56aa5da20..cf2f3bf45 100644 --- a/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java +++ b/bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java @@ -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(); if (annotation.annotationType().equals(RelatedOrderedSetElements.class)) return new RelatedOrderedSetElementsRuleFactory(); + if (annotation.annotationType().equals(LinkedList.class)) + return new LinkedListRuleFactory(); return null; } @@ -264,6 +271,8 @@ public class MappingSchemas { return new RelatedElementsRuleFactory2(); if (annotation.annotationType().equals(OrderedElementsGet.class)) return new OrderedElementsRuleFactory(); + if (annotation.annotationType().equals(LinkedListGet.class)) + return new LinkedListRuleFactory2<>(); return null; }