X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.db.common%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fcommon%2Futils%2FOrderedSetUtils.java;h=8e8171f85273e460bdf519df9eab706ba395b539;hb=HEAD;hp=3e2331a8c63f66a0291a9928369c5136be6b4438;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/OrderedSetUtils.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/OrderedSetUtils.java index 3e2331a8c..8e8171f85 100644 --- a/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/OrderedSetUtils.java +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/OrderedSetUtils.java @@ -1,626 +1,631 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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 - *******************************************************************************/ -package org.simantics.db.common.utils; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -import org.simantics.databoard.Bindings; -import org.simantics.db.AsyncReadGraph; -import org.simantics.db.ReadGraph; -import org.simantics.db.Resource; -import org.simantics.db.WriteGraph; -import org.simantics.db.WriteOnlyGraph; -import org.simantics.db.common.request.ReadRequest; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.exception.RuntimeDatabaseException; -import org.simantics.db.exception.ValidationException; -import org.simantics.db.function.DbFunction; -import org.simantics.db.procedure.AsyncMultiProcedure; -import org.simantics.layer0.Layer0; -import org.simantics.utils.datastructures.Pair; - -public class OrderedSetUtils { - - /** - * Returns true, if l contains the element el. - */ - public static boolean contains(ReadGraph g, Resource l, Resource el) throws DatabaseException { - return g.hasStatement(el, l) && !l.equals(el); - } - - /** - * Returns the next element in the ordered set or l, - * if el is the last element. Called for el, returns - * the first element in the set. - */ - public static Resource next(ReadGraph g, Resource l, Resource el) throws DatabaseException { - Collection nexts = g.getObjects(el, l); - if(nexts.size() != 1) - throw new InvalidOrderedSetException("Invalid list element: " + l + " " + el + " " + nexts.size() + " successors."); - for(Resource r : nexts) - return r; - return null; - } - - public static void forNext(AsyncReadGraph g, final Resource l, Resource el, final AsyncMultiProcedure procedure) { - g.forEachObject(el, l, new AsyncMultiProcedure() { - - @Override - public void exception(AsyncReadGraph graph, Throwable t) { - procedure.exception(graph, t); - } - - @Override - public void finished(AsyncReadGraph graph) { - } - - @Override - public void execute(AsyncReadGraph graph, Resource nel) { - if(!nel.equals(l)) { - procedure.execute(graph, nel); - forNext(graph, l, nel, procedure); - } - } - }); -// Collection nexts = g.getObjects(el, l); -// if(nexts.size() != 1) -// throw new NoSingleResultException("Invalid list element: " + nexts.size() + " successors."); -// for(Resource r : nexts) -// return r; -// return null; - } - - /** - * Returns the previouse element in the ordered set or l, - * if el is the first element. Called for el, returns - * the last element in the set. - */ - public static Resource prev(ReadGraph g, Resource l, Resource el) throws DatabaseException { - Collection prevs = g.getObjects(el, g.getInverse(l)); - if(prevs.size() != 1) { - throw new InvalidOrderedSetException("Invalid list element, " + prevs.size() + " predecessors."); - } - for(Resource r : prevs) - return r; - return null; - } - - /** - * Adds a given elements el to the list l. Returns - * true, if the element was really added. - */ - public static boolean add(WriteGraph g, Resource l, Resource el) throws DatabaseException { - if(g.hasStatement(el, l)) - return false; - Resource back = prev(g, l, l); - g.denyStatement(back, l, l); - g.claim(back, l, el); - g.claim(el, l, l); - return true; - } - - /** - * Adds a given elements el to the list l. Returns - * true, if the element was really added. - */ - public static boolean addFirst(WriteGraph g, Resource l, Resource el) throws DatabaseException { - return addAfter(g, l, l, el); - } - - public static boolean addAll(WriteGraph g, Resource l, Iterable els) throws DatabaseException { - for(Resource r : els) - if(g.hasStatement(r, l)) - return false; - Resource cur = prev(g, l, l); - g.denyStatement(cur, l, l); - for(Resource r : els) { - g.claim(cur, l, r); - cur = r; - } - g.claim(cur, l, l); - return true; - } - - public static boolean addAllNew(WriteGraph g, Resource l, Iterable els) throws DatabaseException { - Resource cur = prev(g, l, l); - Resource inv = g.getInverse(l); - g.deny(cur, l, inv, l); - for(Resource r : els) { - g.claim(cur, l, inv, r); - cur = r; - } - g.claim(cur, l, inv, l); - return true; - } - - public static boolean addAfter(WriteGraph g, Resource l, Resource pos, Resource el) throws DatabaseException { - if(g.hasStatement(el, l)) - return false; - Resource next = next(g, l, pos); - g.denyStatement(pos, l, next); - g.claim(pos, l, el); - g.claim(el, l, next); - return true; - } - - public static boolean addBefore(WriteGraph g, Resource l, Resource pos, Resource el) throws DatabaseException { - if(g.hasStatement(el, l)) - return false; - Resource prev = prev(g, l, pos); - g.denyStatement(prev, l, pos); - g.claim(prev, l, el); - g.claim(el, l, pos); - return true; - } - - /** - * Removes a given elements el from the list l. Returns - * true, if the element was really removed. - */ - public static boolean remove(WriteGraph g, Resource l, Resource el) throws DatabaseException { - Collection nexts = g.getObjects(el, l); - if(nexts.size() == 0) - return false; - if(nexts.size() != 1) - throw new InvalidOrderedSetException("Invalid list element."); - Collection prevs = g.getObjects(el, g.getInverse(l)); - if(prevs.size() != 1) - throw new InvalidOrderedSetException("Invalid list element."); - - for(Resource p : prevs) - for(Resource n : nexts) { - g.denyStatement(p, l, el); - g.denyStatement(el, l, n); - g.claim(p, l, n); - return true; - } - return true; - } - - public static List removeList(WriteGraph g, Resource l) throws DatabaseException { - List els = toList(g, l); - for(Resource el : els) - g.deny(el, l); - g.deny(l, l); - Resource inv = g.getInverse(l); - g.deny(l); - g.deny(inv); - return els; - } - - public static void replace(WriteGraph g, Resource l, Resource oldEl, Resource newEl) throws DatabaseException { - Collection nexts = g.getObjects(oldEl, l); - if(nexts.size() != 1) - throw new InvalidOrderedSetException("Invalid list element."); - Collection prevs = g.getObjects(oldEl, g.getInverse(l)); - if(prevs.size() != 1) - throw new InvalidOrderedSetException("Invalid list element."); - - for(Resource p : prevs) - for(Resource n : nexts) { - g.denyStatement(p, l, oldEl); - g.denyStatement(oldEl, l, n); - g.claim(p, l, newEl); - g.claim(newEl, l, n); - return; - } - } - - /** - * Converts ordered set into a list. - */ - public static List toList(ReadGraph g, Resource l) throws DatabaseException { - ArrayList ret = new ArrayList(); - Resource cur = l; - while(true) { - cur = next(g, l, cur); - if(cur.equals(l)) - return ret; - ret.add(cur); - } - } - - /** - * Converts ordered set into a list. - */ - public static void forEach(AsyncReadGraph g, final Resource l, final AsyncMultiProcedure procedure) { - g.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - for(Resource r : toList(graph, l)) - procedure.execute(graph, r); - } - - }); - } - - /** - * Creates an empty ordered set. - */ - public static Resource create(WriteOnlyGraph g, Resource type) throws DatabaseException { - Layer0 l0 = g.getService(Layer0.class); - Resource l = g.newResource(); - g.claim(l, l0.InstanceOf, null, type); - g.claim(l, l0.SubrelationOf, null, l0.HasNext); - Resource invL = g.newResource(); - g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); - g.claim(l, l0.InverseOf, l0.InverseOf, invL); - g.claim(l, l, invL, l); - return l; - } - - /** - * Creates an ordered set containing the given elements. - * It is assumed that the elements do not contain duplicates. - */ - @Deprecated - public static Resource create(WriteOnlyGraph g, Resource type, Iterable c) throws DatabaseException { - Layer0 l0 = g.getService(Layer0.class); - Resource l = g.newResource(); - g.claim(l, l0.InstanceOf, null, type); - g.claim(l, l0.SubrelationOf, null, l0.HasNext); - Resource invL = g.newResource(); - g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); - g.claim(l, l0.InverseOf, l0.InverseOf, invL); - Resource cur = l; - for(Resource r : c) { - g.claim(cur, l, invL, r); - cur = r; - } - g.claim(cur, l, invL, l); - return l; - } - - public static Resource create(WriteOnlyGraph g, Resource type, String name, Iterable c) throws DatabaseException { - return createExisting(g, g.newResource(), type, name, c); - } - - public static Resource createExisting(WriteOnlyGraph g, Resource l, Resource type, String name, Iterable c) throws DatabaseException { - Layer0 l0 = g.getService(Layer0.class); - g.claim(l, l0.InstanceOf, null, type); - g.claim(l, l0.SubrelationOf, null, l0.HasNext); - g.addLiteral(l, l0.HasName, l0.NameOf, l0.String, name, Bindings.STRING); - Resource invL = g.newResource(); - g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); - g.addLiteral(invL, l0.HasName, l0.NameOf, l0.String, "Inverse", Bindings.STRING); - g.claim(l, l0.InverseOf, l0.InverseOf, invL); - g.claim(l, l0.ConsistsOf, l0.PartOf, invL); - Resource cur = l; - for(Resource r : c) { - g.claim(cur, l, invL, r); - cur = r; - } - g.claim(cur, l, invL, l); - return l; - } - - public static Resource create(WriteOnlyGraph g, Resource type, Resource ... c) throws DatabaseException { - Layer0 l0 = g.getService(Layer0.class); - Resource l = g.newResource(); - g.claim(l, l0.InstanceOf, null, type); - g.claim(l, l0.SubrelationOf, null, l0.HasNext); - Resource invL = g.newResource(); - g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); - g.claim(l, l0.InverseOf, l0.InverseOf, invL); - Resource cur = l; - for(Resource r : c) { - g.claim(cur, l, invL, r); - cur = r; - } - g.claim(cur, l, invL, l); - return l; - } - - public static Resource createExisting(WriteGraph g, Resource l, Resource ... c) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(g); - g.claim(l, l0.SubrelationOf, null, l0.HasNext); - Resource invL = g.newResource(); - g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); - g.claim(l, l0.InverseOf, l0.InverseOf, invL); - Resource cur = l; - for(Resource r : c) { - g.claim(cur, l, invL, r); - cur = r; - } - g.claim(cur, l, invL, l); - return l; - } - -// public static Resource create(GraphWriter graph, Resource type, Iterable c) throws DatabaseException { -// ReadGraph g = w.getGraph(); -// Builtins b = g.getBuiltins(); -// Resource l = w.create(type).get(); -// w.let(b.SubrelationOf, b.IsRelatedTo); -// w.createInverse(l).let(b.SubrelationOf, g.getInverse(b.IsRelatedTo)); -// -// Resource cur = l; -// for(Resource r : c) { -// w.stat(cur, l, r); -// cur = r; -// } -// w.stat(cur, l, l); -// return l; -// } - - public static class OrderedSetIterator implements ListIterator { - - ReadGraph g; - Resource l; - Resource prev; - Resource next; - int index; - boolean direction; - - WriteGraph getWriteGraph() { - if (!(g instanceof WriteGraph)) - throw new UnsupportedOperationException(""); - return (WriteGraph) g; - } - - public OrderedSetIterator(ReadGraph g, Resource l) throws DatabaseException { - this.g = g; - this.l = l; - this.prev = l; - this.next = OrderedSetUtils.next(g, l, l); - this.index = 0; - } - - @Override - public boolean hasNext() { - return !next.equals(l); - } - - @Override - public Resource next() { - prev = next; - try { - next = OrderedSetUtils.next(g, l, next); - } catch (DatabaseException e) { - throw new RuntimeDatabaseException(e); - } - ++index; - direction = true; - return prev; - } - - @Override - public void remove() { - try { - WriteGraph wg = getWriteGraph(); - if(direction) { - OrderedSetUtils.remove(wg, l, prev); - prev = OrderedSetUtils.prev(wg, l, next); - } - else { - OrderedSetUtils.remove(wg, l, next); - next = OrderedSetUtils.next(wg, l, prev); - } - } catch (DatabaseException e) { - throw new RuntimeDatabaseException(e); - } - } - - @Override - public void add(Resource e) { - try { - WriteGraph wg = getWriteGraph(); - wg.denyStatement(prev, l, next); - wg.claim(prev, l, e); - wg.claim(e, l, next); - prev = e; - } catch (DatabaseException ex) { - throw new RuntimeDatabaseException(ex); - } - } - - @Override - public boolean hasPrevious() { - return !prev.equals(l); - } - - @Override - public int nextIndex() { - return index; - } - - @Override - public Resource previous() { - try { - next = prev; - prev = OrderedSetUtils.prev(g, l, prev); - --index; - direction = false; - return next; - } catch (DatabaseException ex) { - throw new RuntimeDatabaseException(ex); - } - } - - @Override - public int previousIndex() { - return index-1; - } - - @Override - public void set(Resource e) { - try { - WriteGraph wg = getWriteGraph(); - if(direction) { - OrderedSetUtils.replace(wg, l, prev, e); - prev = e; - } - else { - OrderedSetUtils.replace(wg, l, next, e); - next = e; - } - } catch (DatabaseException ex) { - throw new RuntimeDatabaseException(ex); - } - } - - } - - public static ListIterator iterator(ReadGraph g, Resource l) throws DatabaseException { - return new OrderedSetIterator(g, l); - } - - public static boolean set(WriteGraph g, Resource l, Iterable els) throws DatabaseException { - - // Compute delta - Set> removed = new HashSet>(); - Collection> added = new ArrayList>(); - Resource cur = l; - do { - Resource temp = next(g, l, cur); - removed.add(new Pair(cur, temp)); - cur = temp; - } while(!cur.equals(l)); - - cur = l; - for(Resource temp : els) { - Pair pair = new Pair(cur, temp); - if(!removed.remove(pair)) - added.add(pair); - cur = temp; - } - - { - Pair pair = new Pair(cur, l); - if(!removed.remove(pair)) - added.add(pair); - } - - // Apply - if(added.isEmpty() && removed.isEmpty()) - return false; - for(Pair pair : removed) - g.denyStatement(pair.first, l, pair.second); - for(Pair pair : added) - g.claim(pair.first, l, pair.second); - return true; - } - - /** - * Retrieves the owner list the specified list element - * - * @param g - * @param el a possible element of a list of the specified type - * @param listBaseRelation a base relation of the list to look for - * @return - */ - public static Resource getSingleOwnerList(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { - Collection result = getOwnerLists(g, el, listBaseRelation); - if (result.size() != 1) - throw new ValidationException(NameUtils.getSafeName(g, el) + " is part of " + result.size() + " lists of base type " + NameUtils.getSafeName(g, listBaseRelation) + ", expected only one list."); - return result.iterator().next(); - } - - public static Resource getSingleOwnerList(ReadGraph g, Resource el) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(g); - Collection result = getOwnerLists(g, el, l0.OrderedSet); - if (result.size() != 1) - throw new ValidationException(NameUtils.getSafeName(g, el) + " is part of " + result.size() + " lists of base type L0.OrderedSet, expected only one list."); - return result.iterator().next(); - } - - public static Collection getSubjects(ReadGraph g, Resource object) throws DatabaseException { - Collection result = new ArrayList(1); - Layer0 l0 = Layer0.getInstance(g); - for(Resource pred : g.getPredicates(object)) { - if(g.isInstanceOf(pred, l0.OrderedSet) && !pred.equals(object)) - result.add(pred); - } - return result; - } - - private static void forSubjects(ReadGraph g, Resource object, DbFunction consumer) throws DatabaseException { - for (Resource pred : g.getPredicates(object)) { - if (!pred.equals(object)) - if (!consumer.apply(pred)) - break; - } - } - - /** - * Retrieves the owner list the specified list element - * - * @param g - * @param el a possible element of a list of the specified type - * @param listBaseRelation a base relation of the list to look for - * @return - */ - public static Collection getOwnerLists(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { - Collection result = null; - Collection rs = getSubjects(g, el); - for (Resource r : rs) { - if (g.isInstanceOf(r, listBaseRelation)) { - if (result == null) - result = new ArrayList(2); - result.add(r); - } - } - if (result == null) - result = Collections.emptyList(); - return result; - } - - private static class PossibleOwnerList implements DbFunction { - private ReadGraph graph; - private final Resource listBaseRelation; - public Layer0 L0; - public Resource result; - - PossibleOwnerList(ReadGraph graph, Resource listBaseRelation) { - this.graph = graph; - this.listBaseRelation = listBaseRelation; - this.L0 = Layer0.getInstance(graph); - } - - @Override - public Boolean apply(Resource t) throws DatabaseException { - Set types = graph.getTypes(t); - if (types.contains(L0.OrderedSet) && types.contains(listBaseRelation)) { - if (result != null) { - result = null; - return false; - } - result = t; - } - return true; - } - } - - /** - * Retrieves a possible single owner list the specified list element - * - * @param g - * @param el - * a possible element of a list of the specified type - * @param listBaseRelation - * a base relation of the list to look for - * @return null if there is zero or more than one owner lists - * with specified base relation - */ - public static Resource getPossibleOwnerList(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { - PossibleOwnerList proc = new PossibleOwnerList(g, listBaseRelation); - forSubjects(g, el, proc); - return proc.result; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2018 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 + *******************************************************************************/ +package org.simantics.db.common.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import org.simantics.databoard.Bindings; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.WriteOnlyGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.exception.ValidationException; +import org.simantics.db.function.DbFunction; +import org.simantics.db.procedure.AsyncMultiProcedure; +import org.simantics.layer0.Layer0; +import org.simantics.utils.datastructures.Pair; + +public class OrderedSetUtils { + + /** + * Returns true, if l contains the element el. + */ + public static boolean contains(ReadGraph g, Resource l, Resource el) throws DatabaseException { + return g.hasStatement(el, l) && !l.equals(el); + } + + /** + * Returns the next element in the ordered set or l, + * if el is the last element. Called for el, returns + * the first element in the set. + */ + public static Resource next(ReadGraph g, Resource l, Resource el) throws DatabaseException { + Collection nexts = g.getObjects(el, l); + if(nexts.size() != 1) + throw new InvalidOrderedSetException("Invalid list element: " + l + " " + el + " " + nexts.size() + " successors."); + for(Resource r : nexts) + return r; + return null; + } + + public static void forNext(AsyncReadGraph g, final Resource l, Resource el, final AsyncMultiProcedure procedure) { + g.forEachObject(el, l, new AsyncMultiProcedure() { + + @Override + public void exception(AsyncReadGraph graph, Throwable t) { + procedure.exception(graph, t); + } + + @Override + public void finished(AsyncReadGraph graph) { + } + + @Override + public void execute(AsyncReadGraph graph, Resource nel) { + if(!nel.equals(l)) { + procedure.execute(graph, nel); + forNext(graph, l, nel, procedure); + } + } + }); +// Collection nexts = g.getObjects(el, l); +// if(nexts.size() != 1) +// throw new NoSingleResultException("Invalid list element: " + nexts.size() + " successors."); +// for(Resource r : nexts) +// return r; +// return null; + } + + /** + * Returns the previouse element in the ordered set or l, + * if el is the first element. Called for el, returns + * the last element in the set. + */ + public static Resource prev(ReadGraph g, Resource l, Resource el) throws DatabaseException { + Collection prevs = g.getObjects(el, g.getInverse(l)); + if(prevs.size() != 1) { + throw new InvalidOrderedSetException("Invalid list element, " + prevs.size() + " predecessors."); + } + for(Resource r : prevs) + return r; + return null; + } + + /** + * Adds a given elements el to the list l. Returns + * true, if the element was really added. + */ + public static boolean add(WriteGraph g, Resource l, Resource el) throws DatabaseException { + if(g.hasStatement(el, l)) + return false; + Resource back = prev(g, l, l); + g.denyStatement(back, l, l); + g.claim(back, l, el); + g.claim(el, l, l); + return true; + } + + /** + * Adds a given elements el to the list l. Returns + * true, if the element was really added. + */ + public static boolean addFirst(WriteGraph g, Resource l, Resource el) throws DatabaseException { + return addAfter(g, l, l, el); + } + + public static boolean addAll(WriteGraph g, Resource l, Iterable els) throws DatabaseException { + for(Resource r : els) + if(g.hasStatement(r, l)) + return false; + Resource cur = prev(g, l, l); + g.denyStatement(cur, l, l); + for(Resource r : els) { + g.claim(cur, l, r); + cur = r; + } + g.claim(cur, l, l); + return true; + } + + public static boolean addAllNew(WriteGraph g, Resource l, Iterable els) throws DatabaseException { + Resource cur = prev(g, l, l); + Resource inv = g.getInverse(l); + g.deny(cur, l, inv, l); + for(Resource r : els) { + g.claim(cur, l, inv, r); + cur = r; + } + g.claim(cur, l, inv, l); + return true; + } + + public static boolean addAfter(WriteGraph g, Resource l, Resource pos, Resource el) throws DatabaseException { + if(g.hasStatement(el, l)) + return false; + Resource next = next(g, l, pos); + g.denyStatement(pos, l, next); + g.claim(pos, l, el); + g.claim(el, l, next); + return true; + } + + public static boolean addBefore(WriteGraph g, Resource l, Resource pos, Resource el) throws DatabaseException { + if(g.hasStatement(el, l)) + return false; + Resource prev = prev(g, l, pos); + g.denyStatement(prev, l, pos); + g.claim(prev, l, el); + g.claim(el, l, pos); + return true; + } + + /** + * Removes a given elements el from the list l. Returns + * true, if the element was really removed. + */ + public static boolean remove(WriteGraph g, Resource l, Resource el) throws DatabaseException { + Collection nexts = g.getObjects(el, l); + if(nexts.size() == 0) + return false; + if(nexts.size() != 1) + throw new InvalidOrderedSetException("Invalid list element."); + Collection prevs = g.getObjects(el, g.getInverse(l)); + if(prevs.size() != 1) + throw new InvalidOrderedSetException("Invalid list element."); + + for(Resource p : prevs) + for(Resource n : nexts) { + g.denyStatement(p, l, el); + g.denyStatement(el, l, n); + g.claim(p, l, n); + return true; + } + return true; + } + + public static List removeList(WriteGraph g, Resource l) throws DatabaseException { + List els = toList(g, l); + for(Resource el : els) + g.deny(el, l); + g.deny(l, l); + Resource inv = g.getInverse(l); + g.deny(l); + g.deny(inv); + return els; + } + + public static void replace(WriteGraph g, Resource l, Resource oldEl, Resource newEl) throws DatabaseException { + Collection nexts = g.getObjects(oldEl, l); + if(nexts.size() != 1) + throw new InvalidOrderedSetException("Invalid list element."); + Collection prevs = g.getObjects(oldEl, g.getInverse(l)); + if(prevs.size() != 1) + throw new InvalidOrderedSetException("Invalid list element."); + + for(Resource p : prevs) + for(Resource n : nexts) { + g.denyStatement(p, l, oldEl); + g.denyStatement(oldEl, l, n); + g.claim(p, l, newEl); + g.claim(newEl, l, n); + return; + } + } + + /** + * Reorders elements with a minimum number of writes. The set of elements must remain the same. + */ + public static void reorder(WriteGraph g, Resource l, Iterable order) throws DatabaseException { + Resource newPrev = l; + for (Resource r : order) { + Resource prev = OrderedSetUtils.prev(g, l, r); + if (!prev.equals(newPrev)) { + g.deny(prev, l, r); + g.claim(newPrev, l, r); + } + newPrev = r; + } + Resource newLast = newPrev; + Resource last = OrderedSetUtils.prev(g, l, l); + if (!last.equals(newLast)) { + g.deny(last, l, l); + g.claim(newLast, l, l); + } + } + + /** + * Converts ordered set into a list. + */ + public static List toList(ReadGraph g, Resource l) throws DatabaseException { + ArrayList ret = new ArrayList(); + Resource cur = l; + while(true) { + cur = next(g, l, cur); + if(cur.equals(l)) + return ret; + ret.add(cur); + } + } + + /** + * Creates an empty ordered set. + */ + public static Resource create(WriteOnlyGraph g, Resource type) throws DatabaseException { + Layer0 l0 = g.getService(Layer0.class); + Resource l = g.newResource(); + g.claim(l, l0.InstanceOf, null, type); + g.claim(l, l0.SubrelationOf, null, l0.HasNext); + Resource invL = g.newResource(); + g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); + g.claim(l, l0.InverseOf, l0.InverseOf, invL); + g.claim(l, l, invL, l); + return l; + } + + /** + * Creates an ordered set containing the given elements. + * It is assumed that the elements do not contain duplicates. + */ + @Deprecated + public static Resource create(WriteOnlyGraph g, Resource type, Iterable c) throws DatabaseException { + Layer0 l0 = g.getService(Layer0.class); + Resource l = g.newResource(); + g.claim(l, l0.InstanceOf, null, type); + g.claim(l, l0.SubrelationOf, null, l0.HasNext); + Resource invL = g.newResource(); + g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); + g.claim(l, l0.InverseOf, l0.InverseOf, invL); + Resource cur = l; + for(Resource r : c) { + g.claim(cur, l, invL, r); + cur = r; + } + g.claim(cur, l, invL, l); + return l; + } + + public static Resource create(WriteOnlyGraph g, Resource type, String name, Iterable c) throws DatabaseException { + return createExisting(g, g.newResource(), type, name, c); + } + + public static Resource createExisting(WriteOnlyGraph g, Resource l, Resource type, String name, Iterable c) throws DatabaseException { + Layer0 l0 = g.getService(Layer0.class); + g.claim(l, l0.InstanceOf, null, type); + g.claim(l, l0.SubrelationOf, null, l0.HasNext); + g.addLiteral(l, l0.HasName, l0.NameOf, l0.String, name, Bindings.STRING); + Resource invL = g.newResource(); + g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); + g.addLiteral(invL, l0.HasName, l0.NameOf, l0.String, "Inverse", Bindings.STRING); + g.claim(l, l0.InverseOf, l0.InverseOf, invL); + g.claim(l, l0.ConsistsOf, l0.PartOf, invL); + Resource cur = l; + for(Resource r : c) { + g.claim(cur, l, invL, r); + cur = r; + } + g.claim(cur, l, invL, l); + return l; + } + + public static Resource create(WriteOnlyGraph g, Resource type, Resource ... c) throws DatabaseException { + Layer0 l0 = g.getService(Layer0.class); + Resource l = g.newResource(); + g.claim(l, l0.InstanceOf, null, type); + g.claim(l, l0.SubrelationOf, null, l0.HasNext); + Resource invL = g.newResource(); + g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); + g.claim(l, l0.InverseOf, l0.InverseOf, invL); + Resource cur = l; + for(Resource r : c) { + g.claim(cur, l, invL, r); + cur = r; + } + g.claim(cur, l, invL, l); + return l; + } + + public static Resource createExisting(WriteGraph g, Resource l, Resource ... c) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + g.claim(l, l0.SubrelationOf, null, l0.HasNext); + Resource invL = g.newResource(); + g.claim(invL, l0.SubrelationOf, null, l0.HasPrevious); + g.claim(l, l0.InverseOf, l0.InverseOf, invL); + Resource cur = l; + for(Resource r : c) { + g.claim(cur, l, invL, r); + cur = r; + } + g.claim(cur, l, invL, l); + return l; + } + +// public static Resource create(GraphWriter graph, Resource type, Iterable c) throws DatabaseException { +// ReadGraph g = w.getGraph(); +// Builtins b = g.getBuiltins(); +// Resource l = w.create(type).get(); +// w.let(b.SubrelationOf, b.IsRelatedTo); +// w.createInverse(l).let(b.SubrelationOf, g.getInverse(b.IsRelatedTo)); +// +// Resource cur = l; +// for(Resource r : c) { +// w.stat(cur, l, r); +// cur = r; +// } +// w.stat(cur, l, l); +// return l; +// } + + public static class OrderedSetIterator implements ListIterator { + + ReadGraph g; + Resource l; + Resource prev; + Resource next; + int index; + boolean direction; + + WriteGraph getWriteGraph() { + if (!(g instanceof WriteGraph)) + throw new UnsupportedOperationException(""); + return (WriteGraph) g; + } + + public OrderedSetIterator(ReadGraph g, Resource l) throws DatabaseException { + this.g = g; + this.l = l; + this.prev = l; + this.next = OrderedSetUtils.next(g, l, l); + this.index = 0; + } + + @Override + public boolean hasNext() { + return !next.equals(l); + } + + @Override + public Resource next() { + prev = next; + try { + next = OrderedSetUtils.next(g, l, next); + } catch (DatabaseException e) { + throw new RuntimeDatabaseException(e); + } + ++index; + direction = true; + return prev; + } + + @Override + public void remove() { + try { + WriteGraph wg = getWriteGraph(); + if(direction) { + OrderedSetUtils.remove(wg, l, prev); + prev = OrderedSetUtils.prev(wg, l, next); + } + else { + OrderedSetUtils.remove(wg, l, next); + next = OrderedSetUtils.next(wg, l, prev); + } + } catch (DatabaseException e) { + throw new RuntimeDatabaseException(e); + } + } + + @Override + public void add(Resource e) { + try { + WriteGraph wg = getWriteGraph(); + wg.denyStatement(prev, l, next); + wg.claim(prev, l, e); + wg.claim(e, l, next); + prev = e; + } catch (DatabaseException ex) { + throw new RuntimeDatabaseException(ex); + } + } + + @Override + public boolean hasPrevious() { + return !prev.equals(l); + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public Resource previous() { + try { + next = prev; + prev = OrderedSetUtils.prev(g, l, prev); + --index; + direction = false; + return next; + } catch (DatabaseException ex) { + throw new RuntimeDatabaseException(ex); + } + } + + @Override + public int previousIndex() { + return index-1; + } + + @Override + public void set(Resource e) { + try { + WriteGraph wg = getWriteGraph(); + if(direction) { + OrderedSetUtils.replace(wg, l, prev, e); + prev = e; + } + else { + OrderedSetUtils.replace(wg, l, next, e); + next = e; + } + } catch (DatabaseException ex) { + throw new RuntimeDatabaseException(ex); + } + } + + } + + public static ListIterator iterator(ReadGraph g, Resource l) throws DatabaseException { + return new OrderedSetIterator(g, l); + } + + public static boolean set(WriteGraph g, Resource l, Iterable els) throws DatabaseException { + + // Compute delta + Set> removed = new HashSet>(); + Collection> added = new ArrayList>(); + Resource cur = l; + do { + Resource temp = next(g, l, cur); + removed.add(new Pair(cur, temp)); + cur = temp; + } while(!cur.equals(l)); + + cur = l; + for(Resource temp : els) { + Pair pair = new Pair(cur, temp); + if(!removed.remove(pair)) + added.add(pair); + cur = temp; + } + + { + Pair pair = new Pair(cur, l); + if(!removed.remove(pair)) + added.add(pair); + } + + // Apply + if(added.isEmpty() && removed.isEmpty()) + return false; + for(Pair pair : removed) + g.denyStatement(pair.first, l, pair.second); + for(Pair pair : added) + g.claim(pair.first, l, pair.second); + return true; + } + + /** + * Retrieves the owner list the specified list element + * + * @param g + * @param el a possible element of a list of the specified type + * @param listBaseRelation a base relation of the list to look for + * @return + */ + public static Resource getSingleOwnerList(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { + Collection result = getOwnerLists(g, el, listBaseRelation); + if (result.size() != 1) + throw new ValidationException(NameUtils.getSafeName(g, el) + " is part of " + result.size() + " lists of base type " + NameUtils.getSafeName(g, listBaseRelation) + ", expected only one list."); + return result.iterator().next(); + } + + public static Resource getSingleOwnerList(ReadGraph g, Resource el) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + Collection result = getOwnerLists(g, el, l0.OrderedSet); + if (result.size() != 1) + throw new ValidationException(NameUtils.getSafeName(g, el) + " is part of " + result.size() + " lists of base type L0.OrderedSet, expected only one list."); + return result.iterator().next(); + } + + public static Collection getSubjects(ReadGraph g, Resource object) throws DatabaseException { + Collection result = new ArrayList(1); + Layer0 l0 = Layer0.getInstance(g); + for(Resource pred : g.getPredicates(object)) { + if(g.isInstanceOf(pred, l0.OrderedSet) && !pred.equals(object)) + result.add(pred); + } + return result; + } + + private static void forSubjects(ReadGraph g, Resource object, DbFunction consumer) throws DatabaseException { + for (Resource pred : g.getPredicates(object)) { + if (!pred.equals(object)) + if (!consumer.apply(pred)) + break; + } + } + + /** + * Retrieves the owner list the specified list element + * + * @param g + * @param el a possible element of a list of the specified type + * @param listBaseRelation a base relation of the list to look for + * @return + */ + public static Collection getOwnerLists(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { + Collection result = null; + Collection rs = getSubjects(g, el); + for (Resource r : rs) { + if (g.isInstanceOf(r, listBaseRelation)) { + if (result == null) + result = new ArrayList(2); + result.add(r); + } + } + if (result == null) + result = Collections.emptyList(); + return result; + } + + private static class PossibleOwnerList implements DbFunction { + private ReadGraph graph; + private final Resource listBaseRelation; + public Layer0 L0; + public Resource result; + + PossibleOwnerList(ReadGraph graph, Resource listBaseRelation) { + this.graph = graph; + this.listBaseRelation = listBaseRelation; + this.L0 = Layer0.getInstance(graph); + } + + @Override + public Boolean apply(Resource t) throws DatabaseException { + Set types = graph.getTypes(t); + if (types.contains(L0.OrderedSet) && types.contains(listBaseRelation)) { + if (result != null) { + result = null; + return false; + } + result = t; + } + return true; + } + } + + /** + * Retrieves a possible single owner list the specified list element + * + * @param g + * @param el + * a possible element of a list of the specified type + * @param listBaseRelation + * a base relation of the list to look for + * @return null if there is zero or more than one owner lists + * with specified base relation + */ + public static Resource getPossibleOwnerList(ReadGraph g, Resource el, Resource listBaseRelation) throws DatabaseException { + PossibleOwnerList proc = new PossibleOwnerList(g, listBaseRelation); + forSubjects(g, el, proc); + return proc.result; + } + +}