/******************************************************************************* * 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 objects * will be exactly the objects connected to subject by predicate. * 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 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.info(" 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.info(" 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 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); } }