-/*******************************************************************************\r
- * Copyright (c) 2007, 2013 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.objmap.graph.rules.domain;\r
-\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.exception.DatabaseException;\r
-\r
-/**\r
- * Static utility methods for rule implementations.\r
- * @author Hannu Niemistö\r
- */\r
-public class MappingUtils {\r
-\r
- static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
- \r
- /**\r
- * Adds and removes statements to/from the database so that <code>objects</code>\r
- * will be exactly the objects connected to <code>subject</code> by <code>predicate</code>.\r
- * Returns true if the method made modifications to the database.\r
- */\r
- public static boolean synchronizeStatements(WriteGraph g, Resource subject, Resource predicate, Resource[] objects,\r
- boolean deleteExtraObjects) \r
- throws DatabaseException {\r
- Collection<Resource> currentObjects0 = g.getObjects(subject, predicate);\r
- Resource[] currentObjects = currentObjects0.toArray(new Resource[currentObjects0.size()]);\r
- \r
- Arrays.sort(objects);\r
- Arrays.sort(currentObjects);\r
- \r
- boolean modified = false;\r
- int i=0, j=0; \r
- if(currentObjects.length > 0 && objects.length > 0)\r
- while(true) {\r
- int cmp = currentObjects[i].compareTo(objects[j]);\r
- if(cmp < 0) {\r
- LOGGER.info(" remove statement");\r
- if(deleteExtraObjects)\r
- g.deny(currentObjects[i]);\r
- else\r
- g.denyStatement(subject, predicate, currentObjects[i]); \r
- modified = true;\r
- ++i;\r
- if(i >= currentObjects.length)\r
- break;\r
- }\r
- else if(cmp > 0) {\r
- LOGGER.info(" add statement");\r
- g.claim(subject, predicate, objects[j]);\r
- modified = true;\r
- ++j;\r
- if(j >= objects.length)\r
- break;\r
- }\r
- else {\r
- ++i; ++j;\r
- if(i >= currentObjects.length)\r
- break;\r
- if(j >= objects.length)\r
- break;\r
- }\r
- }\r
- while(i < currentObjects.length) {\r
- if(deleteExtraObjects)\r
- g.deny(currentObjects[i]);\r
- else\r
- g.denyStatement(subject, predicate, currentObjects[i]);\r
- modified = true;\r
- ++i;\r
- }\r
- while(j < objects.length) {\r
- g.claim(subject, predicate, objects[j]);\r
- modified = true;\r
- ++j;\r
- }\r
- return modified;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * 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.
+ * @author Hannu Niemistö
+ */
+public class MappingUtils {
+
+ static final Logger LOGGER = LoggerFactory.getLogger(MappingUtils.class);
+
+ /**
+ * Adds and removes statements to/from the database so that <code>objects</code>
+ * will be exactly the objects connected to <code>subject</code> by <code>predicate</code>.
+ * Returns true if the method made modifications to the database.
+ */
+ public static boolean synchronizeStatements(WriteGraph g, Resource subject, Resource predicate, Resource[] objects,
+ boolean deleteExtraObjects)
+ throws DatabaseException {
+ Collection<Resource> currentObjects0 = g.getObjects(subject, predicate);
+ Resource[] currentObjects = currentObjects0.toArray(new Resource[currentObjects0.size()]);
+
+ Arrays.sort(objects);
+ Arrays.sort(currentObjects);
+
+ boolean modified = false;
+ int i=0, j=0;
+ if(currentObjects.length > 0 && objects.length > 0)
+ while(true) {
+ int cmp = currentObjects[i].compareTo(objects[j]);
+ if(cmp < 0) {
+ LOGGER.trace(" remove statement");
+ if(deleteExtraObjects)
+ g.deny(currentObjects[i]);
+ else
+ g.denyStatement(subject, predicate, currentObjects[i]);
+ modified = true;
+ ++i;
+ if(i >= currentObjects.length)
+ break;
+ }
+ else if(cmp > 0) {
+ LOGGER.trace(" add statement");
+ g.claim(subject, predicate, objects[j]);
+ modified = true;
+ ++j;
+ if(j >= objects.length)
+ break;
+ }
+ else {
+ ++i; ++j;
+ if(i >= currentObjects.length)
+ break;
+ if(j >= objects.length)
+ break;
+ }
+ }
+ while(i < currentObjects.length) {
+ if(deleteExtraObjects)
+ g.deny(currentObjects[i]);
+ else
+ g.denyStatement(subject, predicate, currentObjects[i]);
+ modified = true;
+ ++i;
+ }
+ while(j < objects.length) {
+ g.claim(subject, predicate, objects[j]);
+ modified = true;
+ ++j;
+ }
+ 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);
+ }
+
+}