/*******************************************************************************
* 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);
}
}