diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/AxiomAdapter.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/AxiomAdapter.java index 8ecd2a013..47a63b592 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/AxiomAdapter.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/AxiomAdapter.java @@ -46,7 +46,7 @@ public OWLAxiom toOwlObjectPropertyAssertionAxiom(Axiom axiom) { objectValue); } - OWLAxiom toOwlDataPropertyAssertionAxiom(Axiom axiom) { + public OWLAxiom toOwlDataPropertyAssertionAxiom(Axiom axiom) { final OWLDataProperty dataProperty = dataFactory .getOWLDataProperty(IRI.create(axiom.getAssertion().getIdentifier())); final OWLLiteral dataValue = OwlapiUtils.createOWLLiteralFromValue(axiom.getValue().getValue(), diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/OwlapiAdapter.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/OwlapiAdapter.java index 8c1784c69..ec7783d14 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/OwlapiAdapter.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/OwlapiAdapter.java @@ -19,16 +19,13 @@ import cz.cvut.kbss.ontodriver.descriptor.AxiomDescriptor; import cz.cvut.kbss.ontodriver.descriptor.AxiomValueDescriptor; -import cz.cvut.kbss.ontodriver.descriptor.ReferencedListDescriptor; -import cz.cvut.kbss.ontodriver.descriptor.ReferencedListValueDescriptor; -import cz.cvut.kbss.ontodriver.descriptor.SimpleListDescriptor; -import cz.cvut.kbss.ontodriver.descriptor.SimpleListValueDescriptor; import cz.cvut.kbss.ontodriver.model.Axiom; import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; import cz.cvut.kbss.ontodriver.owlapi.connector.Connector; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; import cz.cvut.kbss.ontodriver.owlapi.exception.OwlapiDriverException; -import cz.cvut.kbss.ontodriver.owlapi.list.ListHandler; +import cz.cvut.kbss.ontodriver.owlapi.list.ReferencedListHandler; +import cz.cvut.kbss.ontodriver.owlapi.list.SimpleListHandler; import cz.cvut.kbss.ontodriver.owlapi.query.OwlapiPreparedStatement; import cz.cvut.kbss.ontodriver.owlapi.query.OwlapiStatement; import cz.cvut.kbss.ontodriver.owlapi.query.StatementExecutorFactory; @@ -215,14 +212,14 @@ public void addTransactionalChanges(Collection changes) { pendingChanges.addAll(changes); } - public ListHandler getSimpleListHandler() { + public SimpleListHandler getSimpleListHandler() { startTransactionIfNotActive(); - return ListHandler.getSimpleListHandler(this, ontologySnapshot); + return new SimpleListHandler(this, ontologySnapshot); } - public ListHandler getReferencedListHandler() { + public ReferencedListHandler getReferencedListHandler() { startTransactionIfNotActive(); - return ListHandler.getReferencedListHandler(this, ontologySnapshot); + return new ReferencedListHandler(this, ontologySnapshot); } public OwlapiStatement createStatement(OwlapiConnection connection) { diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/InferredReferencedListIterator.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/InferredReferencedListIterator.java index b4667a401..f4dee88ae 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/InferredReferencedListIterator.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/InferredReferencedListIterator.java @@ -25,7 +25,9 @@ import cz.cvut.kbss.ontodriver.owlapi.exception.ReasonerNotAvailableException; import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils; import org.semanticweb.owlapi.model.OWLIndividual; +import org.semanticweb.owlapi.model.OWLLiteral; import org.semanticweb.owlapi.model.OWLNamedIndividual; +import org.semanticweb.owlapi.model.OWLObject; import org.semanticweb.owlapi.reasoner.OWLReasoner; import java.util.Collection; @@ -34,7 +36,7 @@ import java.util.NoSuchElementException; import java.util.stream.Collectors; -class InferredReferencedListIterator extends ReferencedListIterator { +class InferredReferencedListIterator extends ReferencedListIterator { private OWLNamedIndividual currentNode; private final OWLReasoner reasoner; @@ -69,20 +71,28 @@ void doStep() { checkMaxSuccessors(currentNextNodeProperty, nextNodes); this.currentNextNodeProperty = hasNextProperty; this.currentNode = nextNodes.iterator().next(); - this.nextItem = reasoner.getObjectPropertyValues(currentNode, hasContentProperty).entities() - .collect(Collectors.toSet()); + this.nextItem = hasContentProperty.isOWLObjectProperty() ? reasoner.getObjectPropertyValues(currentNode, hasContentProperty.asOWLObjectProperty()) + .entities() + .collect(Collectors.toSet()) + : reasoner.getDataPropertyValues(currentNode, hasContentProperty.asOWLDataProperty()); } @Override - NamedResource nextValue() { + T nextValue() { if (!hasNext()) { throw new NoSuchElementException("There are no more elements."); } checkMaxSuccessors(hasContentProperty, nextItem); - final OWLIndividual value = nextItem.iterator().next(); - checkIsNamed(value); + final OWLObject value = nextItem.iterator().next(); doStep(); - return NamedResource.create(value.asOWLNamedIndividual().getIRI().toURI()); + if (value.isIndividual()) { + final OWLIndividual individual = (OWLIndividual) value; + checkIsNamed(individual); + return (T) NamedResource.create(individual.asOWLNamedIndividual().getIRI().toURI()); + } else { + final OWLLiteral literal = (OWLLiteral) value; + return (T) OwlapiUtils.owlLiteralToValue(literal); + } } @Override @@ -91,7 +101,7 @@ List removeWithoutReconnect() { } @Override - List replaceNode(NamedResource newValue) { + List replaceNode(T newValue) { throw new UnsupportedOperationException(); } } diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandler.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandler.java deleted file mode 100644 index 77921345a..000000000 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandler.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * JOPA - * Copyright (C) 2023 Czech Technical University in Prague - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package cz.cvut.kbss.ontodriver.owlapi.list; - -import cz.cvut.kbss.ontodriver.owlapi.AxiomAdapter; -import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; -import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; -import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; -import cz.cvut.kbss.ontodriver.descriptor.*; -import cz.cvut.kbss.ontodriver.model.Axiom; -import cz.cvut.kbss.ontodriver.model.NamedResource; -import org.semanticweb.owlapi.model.OWLOntology; - -import java.util.ArrayList; -import java.util.List; - -public abstract class ListHandler { - - protected final OwlapiAdapter owlapiAdapter; - protected final AxiomAdapter axiomAdapter; - - protected final OWLOntology ontology; - - protected final OntologySnapshot snapshot; - - protected ListHandler(OwlapiAdapter owlapiAdapter, OntologySnapshot snapshot) { - this.owlapiAdapter = owlapiAdapter; - this.axiomAdapter = new AxiomAdapter(snapshot.getDataFactory()); - this.snapshot = snapshot; - this.ontology = snapshot.getOntology(); - } - - public List> loadList(D descriptor) { - final List> list = new ArrayList<>(); - final OwlapiListIterator iterator = iterator(descriptor); - while (iterator.hasNext()) { - list.add(iterator.next()); - } - return list; - } - - public void persistList(V descriptor) { - if (descriptor.getValues().isEmpty()) { - return; - } - owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(createListAxioms(descriptor))); - } - - abstract OwlapiListIterator iterator(ListDescriptor descriptor); - - abstract List createListAxioms(V descriptor); - - public void updateList(V descriptor) { - if (descriptor.getValues().isEmpty()) { - removeObsoleteNodes(iterator(descriptor)); - } else if (isOrigEmpty(descriptor)) { - persistList(descriptor); - } else { - mergeLists(descriptor); - } - } - - abstract boolean isOrigEmpty(V descriptor); - - private void mergeLists(V descriptor) { - final OwlapiListIterator it = iterator(descriptor); - final List values = descriptor.getValues(); - final List changes = new ArrayList<>(values.size()); - int i = 0; - NamedResource lastNode = null; - while (it.hasNext() && i < values.size()) { - final NamedResource newValue = values.get(i); - final NamedResource currentValue = it.nextValue(); - if (!newValue.equals(currentValue)) { - changes.addAll(snapshot.applyChanges(it.replaceNode(newValue))); - } - lastNode = it.getCurrentNode(); - i++; - } - owlapiAdapter.addTransactionalChanges(changes); - assert lastNode != null; - removeObsoleteNodes(it); - addNewNodes(descriptor, i, lastNode); - } - - private void removeObsoleteNodes(OwlapiListIterator iterator) { - if (!iterator.hasNext()) { - return; - } - final List changes = new ArrayList<>(); - while (iterator.hasNext()) { - iterator.next(); - changes.addAll(iterator.removeWithoutReconnect()); - } - owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(changes)); - } - - abstract void addNewNodes(V descriptor, int index, NamedResource lastNode); - - public static ListHandler getSimpleListHandler( - OwlapiAdapter adapter, OntologySnapshot snapshot) { - return new SimpleListHandler(adapter, snapshot); - } - - public static ListHandler getReferencedListHandler( - OwlapiAdapter adapter, OntologySnapshot snapshot) { - return new ReferencedListHandler(adapter, snapshot); - } -} diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIterator.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIterator.java index 15a8c0dfa..999dfa3e1 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIterator.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIterator.java @@ -22,18 +22,19 @@ import cz.cvut.kbss.ontodriver.model.NamedResource; import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; import org.semanticweb.owlapi.model.OWLIndividual; -import org.semanticweb.owlapi.model.OWLObjectProperty; +import org.semanticweb.owlapi.model.OWLObject; +import org.semanticweb.owlapi.model.OWLProperty; import java.util.Collection; import java.util.List; -abstract class OwlapiListIterator { +abstract class OwlapiListIterator { abstract boolean hasNext(); - abstract Axiom next(); + abstract Axiom next(); - abstract NamedResource nextValue(); + abstract T nextValue(); /** * Gets the current list node. @@ -64,9 +65,9 @@ abstract class OwlapiListIterator { * @param newValue The new value to use * @return List of changes to apply */ - abstract List replaceNode(NamedResource newValue); + abstract List replaceNode(T newValue); - static void checkMaxSuccessors(OWLObjectProperty property, Collection successors) { + static void checkMaxSuccessors(OWLProperty property, Collection successors) { if (successors.size() > 1) { throw new IntegrityConstraintViolatedException( "Invalid number of successors. Expected only 1 value of property " + property + ", but got " + diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiLists.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiLists.java index 7deca71cc..850da450a 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiLists.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiLists.java @@ -81,14 +81,14 @@ public List> loadReferencedList(ReferencedListDescriptor de } @Override - public void persistReferencedList(ReferencedListValueDescriptor descriptor) throws OntoDriverException { + public void persistReferencedList(ReferencedListValueDescriptor descriptor) throws OntoDriverException { ensureStateAndArgumentValid(descriptor); adapter.getReferencedListHandler().persistList(descriptor); afterChangeCallback.execute(); } @Override - public void updateReferencedList(ReferencedListValueDescriptor descriptor) throws OntoDriverException { + public void updateReferencedList(ReferencedListValueDescriptor descriptor) throws OntoDriverException { ensureStateAndArgumentValid(descriptor); adapter.getReferencedListHandler().updateList(descriptor); afterChangeCallback.execute(); diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandler.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandler.java index ea1eea0bc..02a2b9a11 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandler.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandler.java @@ -17,53 +17,80 @@ */ package cz.cvut.kbss.ontodriver.owlapi.list; -import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; -import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; -import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; -import cz.cvut.kbss.ontodriver.owlapi.change.MutableAddAxiom; import cz.cvut.kbss.ontodriver.descriptor.ListDescriptor; import cz.cvut.kbss.ontodriver.descriptor.ReferencedListDescriptor; import cz.cvut.kbss.ontodriver.descriptor.ReferencedListValueDescriptor; import cz.cvut.kbss.ontodriver.exception.IdentifierGenerationException; import cz.cvut.kbss.ontodriver.model.Assertion; +import cz.cvut.kbss.ontodriver.model.Axiom; import cz.cvut.kbss.ontodriver.model.AxiomImpl; import cz.cvut.kbss.ontodriver.model.NamedResource; import cz.cvut.kbss.ontodriver.model.Value; +import cz.cvut.kbss.ontodriver.owlapi.AxiomAdapter; +import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; +import cz.cvut.kbss.ontodriver.owlapi.change.MutableAddAxiom; +import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; +import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; import org.semanticweb.owlapi.model.IRI; import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLOntology; import java.util.ArrayList; import java.util.List; -class ReferencedListHandler extends ListHandler { +public class ReferencedListHandler { private static final int NEXT_NODE_GENERATION_THRESHOLD = 100; - ReferencedListHandler(OwlapiAdapter owlapiAdapter, OntologySnapshot snapshot) { - super(owlapiAdapter, snapshot); + protected final OwlapiAdapter owlapiAdapter; + protected final AxiomAdapter axiomAdapter; + + protected final OWLOntology ontology; + + protected final OntologySnapshot snapshot; + + public ReferencedListHandler(OwlapiAdapter owlapiAdapter, OntologySnapshot snapshot) { + this.owlapiAdapter = owlapiAdapter; + this.axiomAdapter = new AxiomAdapter(snapshot.getDataFactory()); + this.snapshot = snapshot; + this.ontology = snapshot.getOntology(); + } + + public List> loadList(ReferencedListDescriptor descriptor) { + final List> list = new ArrayList<>(); + final ReferencedListIterator iterator = iterator(descriptor); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + return list; } - @Override - OwlapiListIterator iterator(ListDescriptor descriptor) { + public void persistList(ReferencedListValueDescriptor descriptor) { + if (descriptor.getValues().isEmpty()) { + return; + } + owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(createListAxioms(descriptor))); + } + + ReferencedListIterator iterator(ListDescriptor descriptor) { assert descriptor instanceof ReferencedListDescriptor; final ReferencedListDescriptor desc = (ReferencedListDescriptor) descriptor; if (desc.getListProperty().isInferred() || desc.getNextNode().isInferred() || desc.getNodeContent().isInferred()) { - return new InferredReferencedListIterator(desc, snapshot, axiomAdapter); + return new InferredReferencedListIterator<>(desc, snapshot, axiomAdapter); } else { - return new ReferencedListIterator(desc, snapshot, axiomAdapter); + return new ReferencedListIterator<>(desc, snapshot, axiomAdapter); } } - @Override - List createListAxioms(ReferencedListValueDescriptor descriptor) { + List createListAxioms(ReferencedListValueDescriptor descriptor) { final ReferencedListNodeGenerator nodeGenerator = new ReferencedListNodeGenerator( descriptor.getListOwner(), descriptor.getNodeContent()); boolean first = true; NamedResource previousNode = descriptor.getListOwner(); nodeGenerator.setIndex(0); - for (NamedResource value : descriptor.getValues()) { + for (V value : descriptor.getValues()) { if (first) { nodeGenerator.setProperty(descriptor.getListProperty()); previousNode = nodeGenerator.addListNode(previousNode, value); @@ -76,14 +103,22 @@ List createListAxioms(ReferencedListValueDescriptor descrip return nodeGenerator.getChanges(); } - @Override - boolean isOrigEmpty(ReferencedListValueDescriptor descriptor) { - final OwlapiListIterator it = iterator(descriptor); + public void updateList(ReferencedListValueDescriptor descriptor) { + if (descriptor.getValues().isEmpty()) { + removeObsoleteNodes(iterator(descriptor)); + } else if (isOrigEmpty(descriptor)) { + persistList(descriptor); + } else { + mergeLists(descriptor); + } + } + + boolean isOrigEmpty(ReferencedListValueDescriptor descriptor) { + final ReferencedListIterator it = iterator(descriptor); return !it.hasNext(); } - @Override - void addNewNodes(ReferencedListValueDescriptor descriptor, int index, NamedResource lastNode) { + void addNewNodes(ReferencedListValueDescriptor descriptor, int index, NamedResource lastNode) { if (index >= descriptor.getValues().size()) { return; } @@ -92,12 +127,45 @@ void addNewNodes(ReferencedListValueDescriptor descriptor, int index, NamedResou nodeGenerator.setProperty(descriptor.getNextNode()); // We know that we are past list head nodeGenerator.setIndex(index); for (; index < descriptor.getValues().size(); index++) { - final NamedResource nextValue = descriptor.getValues().get(index); + final V nextValue = descriptor.getValues().get(index); lastNode = nodeGenerator.addListNode(lastNode, nextValue); } owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(nodeGenerator.getChanges())); } + private void mergeLists(ReferencedListValueDescriptor descriptor) { + final ReferencedListIterator it = iterator(descriptor); + final List values = descriptor.getValues(); + final List changes = new ArrayList<>(values.size()); + int i = 0; + NamedResource lastNode = null; + while (it.hasNext() && i < values.size()) { + final V newValue = values.get(i); + final V currentValue = it.nextValue(); + if (!newValue.equals(currentValue)) { + changes.addAll(snapshot.applyChanges(it.replaceNode(newValue))); + } + lastNode = it.getCurrentNode(); + i++; + } + owlapiAdapter.addTransactionalChanges(changes); + assert lastNode != null; + removeObsoleteNodes(it); + addNewNodes(descriptor, i, lastNode); + } + + private void removeObsoleteNodes(ReferencedListIterator iterator) { + if (!iterator.hasNext()) { + return; + } + final List changes = new ArrayList<>(); + while (iterator.hasNext()) { + iterator.next(); + changes.addAll(iterator.removeWithoutReconnect()); + } + owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(changes)); + } + private class ReferencedListNodeGenerator { private final String baseUri; @@ -125,7 +193,7 @@ private List getChanges() { return changes; } - private NamedResource addListNode(NamedResource previousNode, NamedResource value) { + private NamedResource addListNode(NamedResource previousNode, V value) { assert property != null; final NamedResource node = generateNode(); @@ -137,10 +205,16 @@ private NamedResource addListNode(NamedResource previousNode, NamedResource valu return node; } - private TransactionalChange generateNodeContent(NamedResource node, NamedResource value) { - final OWLAxiom valueAxiom = axiomAdapter - .toOwlObjectPropertyAssertionAxiom(new AxiomImpl<>(node, nodeContentProperty, new Value<>(value))); - return new MutableAddAxiom(ontology, valueAxiom); + private TransactionalChange generateNodeContent(NamedResource node, V value) { + if (nodeContentProperty.getType() == Assertion.AssertionType.OBJECT_PROPERTY) { + final OWLAxiom valueAxiom = axiomAdapter + .toOwlObjectPropertyAssertionAxiom(new AxiomImpl<>(node, nodeContentProperty, new Value<>(value))); + return new MutableAddAxiom(ontology, valueAxiom); + } else { + assert nodeContentProperty.getType() == Assertion.AssertionType.DATA_PROPERTY; + final OWLAxiom valueAxiom = axiomAdapter.toOwlDataPropertyAssertionAxiom(new AxiomImpl<>(node, nodeContentProperty, new Value<>(value))); + return new MutableAddAxiom(ontology, valueAxiom); + } } private NamedResource generateNode() { diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIterator.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIterator.java index 90a0d2723..a82740276 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIterator.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIterator.java @@ -17,6 +17,7 @@ */ package cz.cvut.kbss.ontodriver.owlapi.list; +import cz.cvut.kbss.ontodriver.model.Assertion; import cz.cvut.kbss.ontodriver.owlapi.AxiomAdapter; import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; @@ -33,10 +34,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -class ReferencedListIterator extends OwlapiListIterator { +class ReferencedListIterator extends OwlapiListIterator { final OWLObjectProperty hasNextProperty; - final OWLObjectProperty hasContentProperty; + final OWLProperty hasContentProperty; final OWLOntology ontology; private final OWLDataFactory dataFactory; @@ -47,7 +48,7 @@ class ReferencedListIterator extends OwlapiListIterator { OWLIndividual currentNode; OWLObjectProperty previousNextNodeProperty; OWLObjectProperty currentNextNodeProperty; - Collection nextItem; + Collection nextItem; final ReferencedListDescriptor descriptor; @@ -55,16 +56,27 @@ class ReferencedListIterator extends OwlapiListIterator { AxiomAdapter axiomAdapter) { this.ontology = snapshot.getOntology(); this.dataFactory = snapshot.getDataFactory(); + this.descriptor = descriptor; this.hasNextProperty = dataFactory.getOWLObjectProperty(IRI.create(descriptor.getNextNode().getIdentifier())); - this.hasContentProperty = dataFactory - .getOWLObjectProperty(IRI.create(descriptor.getNodeContent().getIdentifier())); + this.hasContentProperty = assertionToOwlProperty(descriptor.getNodeContent()); this.axiomAdapter = axiomAdapter; this.currentNextNodeProperty = dataFactory .getOWLObjectProperty(IRI.create(descriptor.getListProperty().getIdentifier())); this.previousNextNodeProperty = currentNextNodeProperty; this.currentNode = OwlapiUtils.getIndividual(descriptor.getListOwner(), dataFactory); this.previousNode = currentNode; - this.descriptor = descriptor; + } + + private OWLProperty assertionToOwlProperty(Assertion a) { + switch (a.getType()) { + case OBJECT_PROPERTY: + return dataFactory + .getOWLObjectProperty(IRI.create(descriptor.getNodeContent().getIdentifier())); + case DATA_PROPERTY: + return dataFactory.getOWLDataProperty(IRI.create(descriptor.getNodeContent().getIdentifier())); + default: + throw new IllegalArgumentException("Node content property cannot be type " + a.getType()); + } } @Override @@ -88,28 +100,44 @@ void doStep() { checkIsNamed(node); this.previousNode = currentNode; this.currentNode = node; - this.nextItem = - EntitySearcher.getObjectPropertyValues(node, hasContentProperty, ontology).collect(Collectors.toSet()); + this.nextItem = resolveCurrentContent(); + } + + private Collection resolveCurrentContent() { + if (hasContentProperty.isOWLObjectProperty()) { + return EntitySearcher.getObjectPropertyValues(currentNode, hasContentProperty.asOWLObjectProperty(), ontology) + .collect(Collectors.toSet()); + } else { + assert hasContentProperty.isOWLDataProperty(); + return EntitySearcher.getDataPropertyValues(currentNode, hasContentProperty.asOWLDataProperty(), ontology) + .collect(Collectors.toSet()); + } } @Override - public Axiom next() { - final NamedResource value = nextValue(); + public Axiom next() { + final T value = nextValue(); return axiomAdapter .createAxiom(NamedResource.create(currentNode.asOWLNamedIndividual().getIRI().toURI()), descriptor.getNodeContent(), value); } @Override - NamedResource nextValue() { + T nextValue() { doStep(); if (nextItem.isEmpty()) { throw new NoSuchElementException("There are no more elements."); } checkMaxSuccessors(hasContentProperty, nextItem); - final OWLIndividual value = nextItem.iterator().next(); - checkIsNamed(value); - return NamedResource.create(value.asOWLNamedIndividual().getIRI().toURI()); + final OWLObject value = nextItem.iterator().next(); + if (value.isIndividual()) { + final OWLIndividual individual = (OWLIndividual) value; + checkIsNamed(individual); + return (T) NamedResource.create(individual.asOWLNamedIndividual().getIRI().toURI()); + } else { + final OWLLiteral literal = (OWLLiteral) value; + return (T) OwlapiUtils.owlLiteralToValue(literal); + } } @Override @@ -138,15 +166,22 @@ private OWLIndividual getNextNode() { } @Override - List replaceNode(NamedResource newValue) { + List replaceNode(T newValue) { // We know there is exactly one, because nextItem has to have been called before this method - final OWLIndividual originalContent = nextItem.iterator().next(); - final OWLNamedIndividual newContent = OwlapiUtils.getIndividual(newValue, dataFactory); - final List changes = new ArrayList<>(2); - changes.add(new MutableRemoveAxiom(ontology, - dataFactory.getOWLObjectPropertyAssertionAxiom(hasContentProperty, currentNode, originalContent))); - changes.add(new MutableAddAxiom(ontology, - dataFactory.getOWLObjectPropertyAssertionAxiom(hasContentProperty, currentNode, newContent))); + final OWLObject originalContent = nextItem.iterator().next(); + final List changes; + if (hasContentProperty.isOWLObjectProperty()) { + final OWLNamedIndividual newContent = OwlapiUtils.getIndividual((NamedResource) newValue, dataFactory); + changes = List.of( + new MutableRemoveAxiom(ontology, dataFactory.getOWLObjectPropertyAssertionAxiom(hasContentProperty.asOWLObjectProperty(), currentNode, (OWLIndividual) originalContent)), + new MutableAddAxiom(ontology, dataFactory.getOWLObjectPropertyAssertionAxiom(hasContentProperty.asOWLObjectProperty(), currentNode, newContent))); + } else { + final OWLLiteral newContent = OwlapiUtils.createOWLLiteralFromValue(newValue, descriptor.getNodeContent() + .getLanguage()); + changes = List.of( + new MutableRemoveAxiom(ontology, dataFactory.getOWLDataPropertyAssertionAxiom(hasContentProperty.asOWLDataProperty(), currentNode, (OWLLiteral) originalContent)), + new MutableAddAxiom(ontology, dataFactory.getOWLDataPropertyAssertionAxiom(hasContentProperty.asOWLDataProperty(), currentNode, newContent))); + } return changes; } } diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandler.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandler.java index d2183115b..ff8cd6212 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandler.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandler.java @@ -21,26 +21,54 @@ import cz.cvut.kbss.ontodriver.descriptor.SimpleListDescriptor; import cz.cvut.kbss.ontodriver.descriptor.SimpleListValueDescriptor; import cz.cvut.kbss.ontodriver.model.Assertion; +import cz.cvut.kbss.ontodriver.model.Axiom; import cz.cvut.kbss.ontodriver.model.AxiomImpl; import cz.cvut.kbss.ontodriver.model.NamedResource; import cz.cvut.kbss.ontodriver.model.Value; +import cz.cvut.kbss.ontodriver.owlapi.AxiomAdapter; import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; import cz.cvut.kbss.ontodriver.owlapi.change.MutableAddAxiom; import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLOntology; import java.util.ArrayList; import java.util.List; -class SimpleListHandler extends ListHandler { +public class SimpleListHandler { - SimpleListHandler(OwlapiAdapter adapter, OntologySnapshot snapshot) { - super(adapter, snapshot); + protected final OwlapiAdapter owlapiAdapter; + protected final AxiomAdapter axiomAdapter; + + protected final OWLOntology ontology; + + protected final OntologySnapshot snapshot; + + public SimpleListHandler(OwlapiAdapter adapter, OntologySnapshot snapshot) { + this.owlapiAdapter = adapter; + this.axiomAdapter = new AxiomAdapter(snapshot.getDataFactory()); + this.snapshot = snapshot; + this.ontology = snapshot.getOntology(); + } + + public List> loadList(SimpleListDescriptor descriptor) { + final List> list = new ArrayList<>(); + final SimpleListIterator iterator = iterator(descriptor); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + return list; } - @Override - OwlapiListIterator iterator(ListDescriptor descriptor) { + public void persistList(SimpleListValueDescriptor descriptor) { + if (descriptor.getValues().isEmpty()) { + return; + } + owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(createListAxioms(descriptor))); + } + + SimpleListIterator iterator(ListDescriptor descriptor) { if (descriptor.getListProperty().isInferred() || descriptor.getNextNode().isInferred()) { return new InferredSimpleListIterator(descriptor, snapshot, axiomAdapter); } else { @@ -48,7 +76,6 @@ OwlapiListIterator iterator(ListDescriptor descriptor) { } } - @Override List createListAxioms(SimpleListValueDescriptor descriptor) { final List changes = new ArrayList<>(descriptor.getValues().size()); NamedResource previous = descriptor.getListOwner(); @@ -71,13 +98,54 @@ private OWLAxiom appendNode(NamedResource current, Assertion property, NamedReso return axiomAdapter.toOwlObjectPropertyAssertionAxiom(new AxiomImpl<>(current, property, new Value<>(next))); } - @Override + public void updateList(SimpleListValueDescriptor descriptor) { + if (descriptor.getValues().isEmpty()) { + removeObsoleteNodes(iterator(descriptor)); + } else if (isOrigEmpty(descriptor)) { + persistList(descriptor); + } else { + mergeLists(descriptor); + } + } + boolean isOrigEmpty(SimpleListValueDescriptor descriptor) { - final OwlapiListIterator it = iterator(descriptor); + final SimpleListIterator it = iterator(descriptor); return !it.hasNext(); } - @Override + private void mergeLists(SimpleListValueDescriptor descriptor) { + final SimpleListIterator it = iterator(descriptor); + final List values = descriptor.getValues(); + final List changes = new ArrayList<>(values.size()); + int i = 0; + NamedResource lastNode = null; + while (it.hasNext() && i < values.size()) { + final NamedResource newValue = values.get(i); + final NamedResource currentValue = it.nextValue(); + if (!newValue.equals(currentValue)) { + changes.addAll(snapshot.applyChanges(it.replaceNode(newValue))); + } + lastNode = it.getCurrentNode(); + i++; + } + owlapiAdapter.addTransactionalChanges(changes); + assert lastNode != null; + removeObsoleteNodes(it); + addNewNodes(descriptor, i, lastNode); + } + + private void removeObsoleteNodes(SimpleListIterator iterator) { + if (!iterator.hasNext()) { + return; + } + final List changes = new ArrayList<>(); + while (iterator.hasNext()) { + iterator.next(); + changes.addAll(iterator.removeWithoutReconnect()); + } + owlapiAdapter.addTransactionalChanges(snapshot.applyChanges(changes)); + } + void addNewNodes(SimpleListValueDescriptor descriptor, int index, NamedResource lastNode) { if (index >= descriptor.getValues().size()) { return; diff --git a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIterator.java b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIterator.java index e877cdd18..45159a7d5 100644 --- a/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIterator.java +++ b/ontodriver-owlapi/src/main/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIterator.java @@ -33,7 +33,7 @@ import java.util.*; import java.util.stream.Collectors; -class SimpleListIterator extends OwlapiListIterator { +class SimpleListIterator extends OwlapiListIterator { final OWLObjectProperty hasNextProperty; diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandlerTestBase.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandlerTestBase.java deleted file mode 100644 index c9bd28ba1..000000000 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListHandlerTestBase.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * JOPA - * Copyright (C) 2023 Czech Technical University in Prague - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package cz.cvut.kbss.ontodriver.owlapi.list; - -import cz.cvut.kbss.ontodriver.descriptor.ListDescriptor; -import cz.cvut.kbss.ontodriver.descriptor.ListValueDescriptor; -import cz.cvut.kbss.ontodriver.model.Assertion; -import cz.cvut.kbss.ontodriver.model.Axiom; -import cz.cvut.kbss.ontodriver.model.NamedResource; -import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; -import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; -import cz.cvut.kbss.ontodriver.owlapi.environment.TestUtils; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.semanticweb.owlapi.model.*; -import org.semanticweb.owlapi.reasoner.OWLReasoner; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.spy; - -public abstract class ListHandlerTestBase { - - static final List LIST_ITEMS = initListItems(); - static final NamedResource SUBJECT = NamedResource - .create("http://krizik.felk.cvut.cz/ontologies/jopa#Owner"); - static final Assertion HAS_LIST = Assertion - .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_LIST_PROPERTY), false); - static final Assertion HAS_NEXT = Assertion - .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_NEXT_PROPERTY), false); - static final Assertion HAS_CONTENT = Assertion - .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_CONTENT_PROPERTY), false); - - OWLOntology ontology; - OWLOntologyManager manager; - OWLDataFactory dataFactory; - OWLNamedIndividual individual; - - @Mock - OWLReasoner reasonerMock; - - @Mock - OwlapiAdapter adapterMock; - - D descriptor; - V valueDescriptor; - ListTestHelper testHelper; - ListHandler listHandler; - - private static List initListItems() { - final List lst = new ArrayList<>(10); - for (int i = 0; i < 10; i++) { - lst.add(URI.create("http://krizik.felk.cvut.cz/ontologies/jopa#ListItem_" + i)); - } - return lst; - } - - public void setUp() throws Exception { - final OntologySnapshot realSnapshot = TestUtils.initRealOntology(reasonerMock); - this.ontology = spy(realSnapshot.getOntology()); - this.manager = spy(realSnapshot.getOntologyManager()); - this.dataFactory = realSnapshot.getDataFactory(); - this.individual = dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier())); - } - - abstract V createDescriptor(); - - @Test - public void updateListToEmptyClearsList() { - final List origList = LIST_ITEMS.subList(0, 5); - origList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - listHandler.persistList(valueDescriptor); - - final V updatedDescriptor = createDescriptor(); - listHandler.updateList(updatedDescriptor); - - final List> result = listHandler.loadList(descriptor); - assertTrue(result.isEmpty()); - } - - @Test - public void updateEmptyListWithNonEmptyPersistsNewOne() { - final List updated = LIST_ITEMS.subList(0, 5); - updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - - listHandler.updateList(valueDescriptor); - - final List> result = listHandler.loadList(descriptor); - verifyUpdatedListContent(updated, result); - } - - private void verifyUpdatedListContent(List expected, List> actual) { - assertEquals(expected.size(), actual.size()); - for (int i = 0; i < expected.size(); i++) { - assertEquals(expected.get(i), actual.get(i).getValue().getValue().getIdentifier()); - } - } - - @Test - public void updateListByRemovingElementsFromTheEnd() { - testHelper.persistList(LIST_ITEMS); - final List subList = LIST_ITEMS.subList(0, 5); - subList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - - listHandler.updateList(valueDescriptor); - final List> result = listHandler.loadList(descriptor); - verifyUpdatedListContent(subList, result); - } - - @Test - public void updateListByReplacingSomeElementsButKeepingSize() { - final List origList = LIST_ITEMS.subList(0, 6); - testHelper.persistList(origList); - - final List updated = new ArrayList<>(origList); - updated.set(2, LIST_ITEMS.get(7)); - updated.set(4, LIST_ITEMS.get(9)); - updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - - listHandler.updateList(valueDescriptor); - final List> result = listHandler.loadList(descriptor); - verifyUpdatedListContent(updated, result); - } - - @Test - public void updateListByReplacingSomeElementsAndAddingNewOnes() { - final List origList = LIST_ITEMS.subList(0, 6); - testHelper.persistList(origList); - final List updated = new ArrayList<>(origList); - updated.set(2, LIST_ITEMS.get(7)); - updated.set(3, LIST_ITEMS.get(8)); - updated.add(LIST_ITEMS.get(9)); - updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - - listHandler.updateList(valueDescriptor); - final List> result = listHandler.loadList(descriptor); - verifyUpdatedListContent(updated, result); - } - - @Test - public void updateListByReplacingSomeElementsAndRemovingSome() { - final List origList = LIST_ITEMS.subList(0, 6); - testHelper.persistList(origList); - final List updated = new ArrayList<>(origList); - updated.set(0, LIST_ITEMS.get(7)); - updated.set(1, LIST_ITEMS.get(8)); - updated.remove(updated.size() - 1); - updated.remove(updated.size() - 2); - updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); - - listHandler.updateList(valueDescriptor); - final List> result = listHandler.loadList(descriptor); - verifyUpdatedListContent(updated, result); - } -} diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListTestHelper.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListTestHelper.java index e615a21a0..ae67e0359 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListTestHelper.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ListTestHelper.java @@ -17,6 +17,9 @@ */ package cz.cvut.kbss.ontodriver.owlapi.list; +import cz.cvut.kbss.ontodriver.model.Assertion; +import cz.cvut.kbss.ontodriver.model.Axiom; +import cz.cvut.kbss.ontodriver.model.NamedResource; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; import org.semanticweb.owlapi.model.OWLDataFactory; import org.semanticweb.owlapi.model.OWLNamedIndividual; @@ -24,14 +27,27 @@ import org.semanticweb.owlapi.model.OWLOntologyManager; import java.net.URI; +import java.util.ArrayList; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; + abstract class ListTestHelper { public static final String HAS_LIST_PROPERTY = "http://krizik.felk.cvut.cz/ontologies/2008/6/sequences.owl#hasListProperty"; public static final String HAS_NEXT_PROPERTY = "http://krizik.felk.cvut.cz/ontologies/2008/6/sequences.owl#hasNext"; public static final String HAS_CONTENT_PROPERTY = "http://krizik.felk.cvut.cz/ontologies/2008/6/sequences.owl#hasContent"; + static final List LIST_ITEMS = initListItems(); + static final NamedResource SUBJECT = NamedResource + .create("http://krizik.felk.cvut.cz/ontologies/jopa#Owner"); + static final Assertion HAS_LIST = Assertion + .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_LIST_PROPERTY), false); + static final Assertion HAS_NEXT = Assertion + .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_NEXT_PROPERTY), false); + static final Assertion HAS_CONTENT = Assertion + .createObjectPropertyAssertion(URI.create(ListTestHelper.HAS_CONTENT_PROPERTY), false); + final OWLOntology ontology; final OWLOntologyManager manager; final OWLDataFactory dataFactory; @@ -45,4 +61,19 @@ abstract class ListTestHelper { } abstract void persistList(List items); + + private static List initListItems() { + final List lst = new ArrayList<>(10); + for (int i = 0; i < 10; i++) { + lst.add(URI.create("http://krizik.felk.cvut.cz/ontologies/jopa#ListItem_" + i)); + } + return lst; + } + + static void verifyListContent(List expected, List> actual) { + assertEquals(expected.size(), actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(expected.get(i), actual.get(i).getValue().getValue().getIdentifier()); + } + } } diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIteratorBase.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIteratorBase.java index 986d77c00..35f1f5e14 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIteratorBase.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListIteratorBase.java @@ -32,7 +32,6 @@ import java.util.NoSuchElementException; import java.util.stream.Collectors; -import static cz.cvut.kbss.ontodriver.owlapi.list.ListHandlerTestBase.LIST_ITEMS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -45,18 +44,18 @@ abstract class OwlapiListIteratorBase { ListTestHelper testHelper; AxiomAdapter axiomAdapter; - OwlapiListIterator iterator; + OwlapiListIterator iterator; public void setUp() throws Exception { this.snapshot = TestUtils.initRealOntology(null); this.axiomAdapter = new AxiomAdapter(snapshot.getDataFactory()); } - abstract OwlapiListIterator iterator(); + abstract OwlapiListIterator iterator(); @Test public void nextWithoutMoreElementsThrowsException() { - testHelper.persistList(LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); while (iterator.hasNext()) { iterator.next(); } @@ -65,11 +64,11 @@ public void nextWithoutMoreElementsThrowsException() { @Test public void testBasicIteration() { - testHelper.persistList(LIST_ITEMS); - verifyIterationContent(iterator, LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); + verifyIterationContent(iterator, ListTestHelper.LIST_ITEMS); } - private void verifyIterationContent(OwlapiListIterator it, List expected) { + private void verifyIterationContent(OwlapiListIterator it, List expected) { int i = 0; while (it.hasNext()) { final Axiom item = it.next(); @@ -81,14 +80,14 @@ private void verifyIterationContent(OwlapiListIterator it, List expected) { @Test public void removeWithoutReconnectOnAllElementsClearsTheWholeList() { - testHelper.persistList(LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); final List changes = new ArrayList<>(); while (iterator.hasNext()) { iterator.next(); changes.addAll(iterator.removeWithoutReconnect()); } applyChanges(changes); - final OwlapiListIterator it = iterator(); + final OwlapiListIterator it = iterator(); assertFalse(it.hasNext()); } @@ -101,7 +100,7 @@ protected void applyChanges(List changes) { @Test public void removeWithoutReconnectClearsRestOfList() { - testHelper.persistList(LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); final List changes = new ArrayList<>(); int i = 0; while (iterator.hasNext()) { @@ -112,7 +111,7 @@ public void removeWithoutReconnectClearsRestOfList() { i++; } applyChanges(changes); - final OwlapiListIterator it = iterator(); + final OwlapiListIterator it = iterator(); int count = 0; while (it.hasNext()) { it.next(); @@ -123,23 +122,23 @@ public void removeWithoutReconnectClearsRestOfList() { @Test public void testReplaceHead() { - final List lst = new ArrayList<>(LIST_ITEMS.subList(0, 5)); + final List lst = new ArrayList<>(ListTestHelper.LIST_ITEMS.subList(0, 5)); testHelper.persistList(lst); - lst.set(0, LIST_ITEMS.get(8)); + lst.set(0, ListTestHelper.LIST_ITEMS.get(8)); iterator.next(); final List changes = new ArrayList<>(iterator.replaceNode(NamedResource.create(lst.get(0)))); applyChanges(changes); - final OwlapiListIterator it = iterator(); + final OwlapiListIterator it = iterator(); verifyIterationContent(it, lst); } @Test public void testReplaceNodeInsideList() { - final List lst = new ArrayList<>(LIST_ITEMS.subList(0, 5)); + final List lst = new ArrayList<>(ListTestHelper.LIST_ITEMS.subList(0, 5)); testHelper.persistList(lst); int replaceIndex = 2; - lst.set(replaceIndex, LIST_ITEMS.get(8)); + lst.set(replaceIndex, ListTestHelper.LIST_ITEMS.get(8)); int i = 0; while (iterator.hasNext() && i < replaceIndex) { iterator.next(); @@ -150,16 +149,16 @@ public void testReplaceNodeInsideList() { new ArrayList<>(iterator.replaceNode(NamedResource.create(lst.get(replaceIndex)))); applyChanges(changes); - final OwlapiListIterator it = iterator(); + final OwlapiListIterator it = iterator(); verifyIterationContent(it, lst); } @Test public void testReplaceLastNode() { - final List lst = new ArrayList<>(LIST_ITEMS.subList(0, 5)); + final List lst = new ArrayList<>(ListTestHelper.LIST_ITEMS.subList(0, 5)); testHelper.persistList(lst); int replaceIndex = lst.size() - 1; - lst.set(replaceIndex, LIST_ITEMS.get(8)); + lst.set(replaceIndex, ListTestHelper.LIST_ITEMS.get(8)); int i = 0; while (iterator.hasNext() && i < replaceIndex) { iterator.next(); @@ -170,7 +169,7 @@ public void testReplaceLastNode() { new ArrayList<>(iterator.replaceNode(NamedResource.create(lst.get(replaceIndex)))); applyChanges(changes); - final OwlapiListIterator it = iterator(); + final OwlapiListIterator it = iterator(); verifyIterationContent(it, lst); } } diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListsTest.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListsTest.java index 5a3953580..d1301b985 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListsTest.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/OwlapiListsTest.java @@ -26,7 +26,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static cz.cvut.kbss.ontodriver.owlapi.list.ListHandlerTestBase.*; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -55,7 +54,7 @@ public void setUp() { @Test public void testLoadSimpleList() throws Exception { - final SimpleListDescriptor descriptor = new SimpleListDescriptorImpl(SUBJECT, HAS_LIST, HAS_NEXT); + final SimpleListDescriptor descriptor = new SimpleListDescriptorImpl(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT); lists.loadSimpleList(descriptor); verify(adapterMock).getSimpleListHandler(); verify(simpleListHandlerMock).loadList(descriptor); @@ -63,7 +62,7 @@ public void testLoadSimpleList() throws Exception { @Test public void testPersistSimpleList() throws Exception { - final SimpleListValueDescriptor descriptor = new SimpleListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT); + final SimpleListValueDescriptor descriptor = new SimpleListValueDescriptor(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT); descriptor.addValue(NamedResource.create("http://test")); lists.persistSimpleList(descriptor); verify(simpleListHandlerMock).persistList(descriptor); @@ -72,7 +71,7 @@ public void testPersistSimpleList() throws Exception { @Test public void testUpdateSimpleList() throws Exception { - final SimpleListValueDescriptor descriptor = new SimpleListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT); + final SimpleListValueDescriptor descriptor = new SimpleListValueDescriptor(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT); descriptor.addValue(NamedResource.create("http://test")); lists.updateSimpleList(descriptor); verify(simpleListHandlerMock).updateList(descriptor); @@ -81,16 +80,16 @@ public void testUpdateSimpleList() throws Exception { @Test public void testLoadReferencedList() throws Exception { - final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(SUBJECT, HAS_LIST, HAS_NEXT, - HAS_CONTENT); + final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, + ListTestHelper.HAS_CONTENT); lists.loadReferencedList(descriptor); verify(refListHandlerMock).loadList(descriptor); } @Test public void testPersistReferencedList() throws Exception { - final ReferencedListValueDescriptor descriptor = new ReferencedListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT, - HAS_CONTENT); + final ReferencedListValueDescriptor descriptor = new ReferencedListValueDescriptor<>(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, + ListTestHelper.HAS_CONTENT); descriptor.addValue(NamedResource.create("http://test")); lists.persistReferencedList(descriptor); verify(refListHandlerMock).persistList(descriptor); @@ -99,8 +98,8 @@ public void testPersistReferencedList() throws Exception { @Test public void testUpdateReferencedList() throws Exception { - final ReferencedListValueDescriptor descriptor = new ReferencedListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT, - HAS_CONTENT); + final ReferencedListValueDescriptor descriptor = new ReferencedListValueDescriptor(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, + ListTestHelper.HAS_CONTENT); descriptor.addValue(NamedResource.create("http://test")); lists.updateReferencedList(descriptor); verify(refListHandlerMock).updateList(descriptor); diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandlerTest.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandlerTest.java index b7a8aa450..3b892e155 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandlerTest.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListHandlerTest.java @@ -24,23 +24,71 @@ import cz.cvut.kbss.ontodriver.model.Assertion; import cz.cvut.kbss.ontodriver.model.Axiom; import cz.cvut.kbss.ontodriver.model.NamedResource; +import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; +import cz.cvut.kbss.ontodriver.owlapi.environment.TestUtils; +import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.MockitoAnnotations; -import org.semanticweb.owlapi.model.*; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.semanticweb.owlapi.model.AddAxiom; +import org.semanticweb.owlapi.model.AxiomType; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLDataFactory; +import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom; +import org.semanticweb.owlapi.model.OWLIndividual; +import org.semanticweb.owlapi.model.OWLNamedIndividual; +import org.semanticweb.owlapi.model.OWLObjectProperty; +import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyManager; import org.semanticweb.owlapi.reasoner.NodeSet; +import org.semanticweb.owlapi.reasoner.OWLReasoner; import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNodeSet; import java.net.URI; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -public class ReferencedListHandlerTest - extends ListHandlerTestBase { +@ExtendWith(MockitoExtension.class) +public class ReferencedListHandlerTest { + + OWLOntology ontology; + OWLOntologyManager manager; + OWLDataFactory dataFactory; + OWLNamedIndividual individual; + + @Mock + OWLReasoner reasonerMock; + + @Mock + OwlapiAdapter adapterMock; + + ReferencedListDescriptor descriptor; + ReferencedListValueDescriptor valueDescriptor; + ListTestHelper testHelper; + ReferencedListHandler listHandler; private OWLObjectProperty hasListProperty; private OWLObjectProperty hasNextProperty; @@ -48,21 +96,23 @@ public class ReferencedListHandlerTest @BeforeEach public void setUp() throws Exception { - MockitoAnnotations.openMocks(this); - super.setUp(); - this.descriptor = new ReferencedListDescriptorImpl(SUBJECT, HAS_LIST, HAS_NEXT, HAS_CONTENT); + final OntologySnapshot realSnapshot = TestUtils.initRealOntology(reasonerMock); + this.ontology = spy(realSnapshot.getOntology()); + this.manager = spy(realSnapshot.getOntologyManager()); + this.dataFactory = realSnapshot.getDataFactory(); + this.individual = dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.SUBJECT.getIdentifier())); + this.descriptor = new ReferencedListDescriptorImpl(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, ListTestHelper.HAS_CONTENT); this.valueDescriptor = createDescriptor(); final OntologySnapshot snapshotToUse = new OntologySnapshot(ontology, manager, dataFactory, reasonerMock); - this.testHelper = new ReferencedListTestHelper(snapshotToUse, individual, SUBJECT.toString()); + this.testHelper = new ReferencedListTestHelper(snapshotToUse, individual, ListTestHelper.SUBJECT.toString()); this.listHandler = new ReferencedListHandler(adapterMock, snapshotToUse); - this.hasListProperty = dataFactory.getOWLObjectProperty(IRI.create(HAS_LIST.getIdentifier())); - this.hasNextProperty = dataFactory.getOWLObjectProperty(IRI.create(HAS_NEXT.getIdentifier())); - this.hasContentProperty = dataFactory.getOWLObjectProperty(IRI.create(HAS_CONTENT.getIdentifier())); + this.hasListProperty = dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_LIST.getIdentifier())); + this.hasNextProperty = dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_NEXT.getIdentifier())); + this.hasContentProperty = dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_CONTENT.getIdentifier())); } - @Override - ReferencedListValueDescriptor createDescriptor() { - return new ReferencedListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT, HAS_CONTENT); + ReferencedListValueDescriptor createDescriptor() { + return new ReferencedListValueDescriptor<>(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, ListTestHelper.HAS_CONTENT); } @Test @@ -74,7 +124,7 @@ public void loadListReturnsEmptyListWhenNoHeadIsFound() { @Test public void loadListLoadsSingleElementListWithHeadOnly() { - final List headOnly = LIST_ITEMS.subList(0, 1); + final List headOnly = ListTestHelper.LIST_ITEMS.subList(0, 1); testHelper.persistList(headOnly); final List> result = listHandler.loadList(descriptor); assertEquals(1, result.size()); @@ -83,25 +133,26 @@ public void loadListLoadsSingleElementListWithHeadOnly() { @Test public void loadListWithMultipleItems() { - testHelper.persistList(LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); final List> result = listHandler.loadList(descriptor); - assertEquals(LIST_ITEMS.size(), result.size()); - for (int i = 0; i < LIST_ITEMS.size(); i++) { - assertEquals(LIST_ITEMS.get(i), result.get(i).getValue().getValue().getIdentifier()); + assertEquals(ListTestHelper.LIST_ITEMS.size(), result.size()); + for (int i = 0; i < ListTestHelper.LIST_ITEMS.size(); i++) { + assertEquals(ListTestHelper.LIST_ITEMS.get(i), result.get(i).getValue().getValue().getIdentifier()); } } @Test public void loadingListWithItemWithMultipleSuccessorsThrowsException() { - testHelper.persistList(LIST_ITEMS.subList(0, 5)); - addExtraPropertyValue(ListTestHelper.HAS_NEXT_PROPERTY, LIST_ITEMS.get(8)); + testHelper.persistList(ListTestHelper.LIST_ITEMS.subList(0, 5)); + addExtraPropertyValue(ListTestHelper.HAS_NEXT_PROPERTY, ListTestHelper.LIST_ITEMS.get(8)); assertThrows(IntegrityConstraintViolatedException.class, () -> listHandler.loadList(descriptor)); } private void addExtraPropertyValue(String property, URI value) { final OWLNamedIndividual node = dataFactory .getOWLNamedIndividual(IRI.create( - SUBJECT.getIdentifier().toString() + ReferencedListTestHelper.SEQUENCE_NODE_SUFFIX + "2")); + ListTestHelper.SUBJECT.getIdentifier() + .toString() + ReferencedListTestHelper.SEQUENCE_NODE_SUFFIX + "2")); final OWLObjectProperty hasNext = dataFactory.getOWLObjectProperty(IRI.create(property)); manager.addAxiom(ontology, dataFactory.getOWLObjectPropertyAssertionAxiom(hasNext, node, @@ -110,28 +161,28 @@ private void addExtraPropertyValue(String property, URI value) { @Test public void loadingListWithNodeWithMultipleContentElementsThrowsException() { - testHelper.persistList(LIST_ITEMS.subList(0, 8)); - addExtraPropertyValue(ListTestHelper.HAS_CONTENT_PROPERTY, LIST_ITEMS.get(0)); + testHelper.persistList(ListTestHelper.LIST_ITEMS.subList(0, 8)); + addExtraPropertyValue(ListTestHelper.HAS_CONTENT_PROPERTY, ListTestHelper.LIST_ITEMS.get(0)); assertThrows(IntegrityConstraintViolatedException.class, () -> listHandler.loadList(descriptor)); } @Test public void loadListWithInferredNodeContent() { initReasoner(); - final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(SUBJECT, - HAS_LIST, HAS_NEXT, Assertion.createObjectPropertyAssertion(HAS_CONTENT.getIdentifier(), true)); + final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(ListTestHelper.SUBJECT, + ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, Assertion.createObjectPropertyAssertion(ListTestHelper.HAS_CONTENT.getIdentifier(), true)); final List> result = listHandler.loadList(descriptor); assertEquals(1, result.size()); - assertEquals(LIST_ITEMS.get(0), result.get(0).getValue().getValue().getIdentifier()); + assertEquals(ListTestHelper.LIST_ITEMS.get(0), result.get(0).getValue().getValue().getIdentifier()); } private void initReasoner() { final OWLNamedIndividual node = dataFactory.getOWLNamedIndividual( - IRI.create(SUBJECT + ReferencedListTestHelper.SEQUENCE_NODE_SUFFIX + "0")); - final OWLNamedIndividual owner = dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier())); + IRI.create(ListTestHelper.SUBJECT + ReferencedListTestHelper.SEQUENCE_NODE_SUFFIX + "0")); + final OWLNamedIndividual owner = dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.SUBJECT.getIdentifier())); final NodeSet nodeSet = new OWLNamedIndividualNodeSet(node); when(reasonerMock.getObjectPropertyValues(owner, hasListProperty)).thenReturn(nodeSet); - final OWLNamedIndividual content = dataFactory.getOWLNamedIndividual(IRI.create(LIST_ITEMS.get(0))); + final OWLNamedIndividual content = dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.LIST_ITEMS.get(0))); final NodeSet valueSet = new OWLNamedIndividualNodeSet(content); when(reasonerMock.getObjectPropertyValues(node, hasContentProperty)).thenReturn(valueSet); when(reasonerMock.getObjectPropertyValues(node, hasNextProperty)).thenReturn(new OWLNamedIndividualNodeSet()); @@ -140,11 +191,11 @@ private void initReasoner() { @Test public void loadListWithInferredHead() { initReasoner(); - final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(SUBJECT, - Assertion.createObjectPropertyAssertion(HAS_LIST.getIdentifier(), true), HAS_NEXT, HAS_CONTENT); + final ReferencedListDescriptor descriptor = new ReferencedListDescriptorImpl(ListTestHelper.SUBJECT, + Assertion.createObjectPropertyAssertion(ListTestHelper.HAS_LIST.getIdentifier(), true), ListTestHelper.HAS_NEXT, ListTestHelper.HAS_CONTENT); final List> result = listHandler.loadList(descriptor); assertEquals(1, result.size()); - assertEquals(LIST_ITEMS.get(0), result.get(0).getValue().getValue().getIdentifier()); + assertEquals(ListTestHelper.LIST_ITEMS.get(0), result.get(0).getValue().getValue().getIdentifier()); } @Test @@ -155,12 +206,12 @@ public void persistEmptyListDoesNothing() { @Test public void persistListWithHeadOnly() { - valueDescriptor.addValue(NamedResource.create(LIST_ITEMS.get(0))); + valueDescriptor.addValue(NamedResource.create(ListTestHelper.LIST_ITEMS.get(0))); listHandler.persistList(valueDescriptor); final ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); verify(manager).applyChanges(captor.capture()); final List changes = captor.getValue(); - verifyAddedChanges(changes, LIST_ITEMS.subList(0, 1)); + verifyAddedChanges(changes, ListTestHelper.LIST_ITEMS.subList(0, 1)); verify(adapterMock).addTransactionalChanges(anyList()); } @@ -192,12 +243,114 @@ private void verifyAddedChanges(List changes, List expectedElements) { @Test public void persistListWithMultipleElementsSavesTheList() { - LIST_ITEMS.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + ListTestHelper.LIST_ITEMS.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); listHandler.persistList(valueDescriptor); final ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); verify(manager).applyChanges(captor.capture()); final List changes = captor.getValue(); - verifyAddedChanges(changes, LIST_ITEMS); + verifyAddedChanges(changes, ListTestHelper.LIST_ITEMS); verify(adapterMock).addTransactionalChanges(anyList()); } + + @Test + public void updateListToEmptyClearsList() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 5); + origList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + listHandler.persistList(valueDescriptor); + + final ReferencedListValueDescriptor updatedDescriptor = createDescriptor(); + listHandler.updateList(updatedDescriptor); + + final List> result = listHandler.loadList(descriptor); + assertTrue(result.isEmpty()); + } + + @Test + public void updateEmptyListWithNonEmptyPersistsNewOne() { + final List updated = ListTestHelper.LIST_ITEMS.subList(0, 5); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByRemovingElementsFromTheEnd() { + testHelper.persistList(ListTestHelper.LIST_ITEMS); + final List subList = ListTestHelper.LIST_ITEMS.subList(0, 5); + subList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(subList, result); + } + + @Test + public void updateListByReplacingSomeElementsButKeepingSize() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + + final List updated = new ArrayList<>(origList); + updated.set(2, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(4, ListTestHelper.LIST_ITEMS.get(9)); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByReplacingSomeElementsAndAddingNewOnes() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + final List updated = new ArrayList<>(origList); + updated.set(2, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(3, ListTestHelper.LIST_ITEMS.get(8)); + updated.add(ListTestHelper.LIST_ITEMS.get(9)); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByReplacingSomeElementsAndRemovingSome() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + final List updated = new ArrayList<>(origList); + updated.set(0, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(1, ListTestHelper.LIST_ITEMS.get(8)); + updated.remove(updated.size() - 1); + updated.remove(updated.size() - 2); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + void persistListSupportsPersistingListWithDataPropertyContent() { + final List values = IntStream.range(0, 5).boxed().collect(Collectors.toList()); + final ReferencedListValueDescriptor valueDescriptor = new ReferencedListValueDescriptor<>(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT, Assertion.createDataPropertyAssertion(URI.create(ListTestHelper.HAS_CONTENT_PROPERTY), false)); + values.forEach(valueDescriptor::addValue); + + listHandler.persistList(valueDescriptor); + final ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); + verify(manager).applyChanges(captor.capture()); + final List changes = captor.getValue(); + assertEquals(values.size() * 2, changes.size()); + for (AddAxiom change : changes) { + final OWLAxiom ax = change.getAxiom(); + if (ax.isOfType(AxiomType.DATA_PROPERTY_ASSERTION)) { + final OWLDataPropertyAssertionAxiom dpaAx = (OWLDataPropertyAssertionAxiom) ax; + assertEquals(ListTestHelper.HAS_CONTENT_PROPERTY, dpaAx.getProperty().asOWLDataProperty().getIRI().toString()); + assertThat(values, hasItem((Integer) OwlapiUtils.owlLiteralToValue(dpaAx.getObject()))); + } + } + } } diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIteratorTest.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIteratorTest.java index 8467777ba..b4b7bfa74 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIteratorTest.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/ReferencedListIteratorTest.java @@ -33,13 +33,13 @@ public void setUp() throws Exception { super.setUp(); final OWLNamedIndividual individual = snapshot.getDataFactory().getOWLNamedIndividual(IRI.create(SUBJECT)); this.testHelper = new ReferencedListTestHelper(snapshot, individual, SUBJECT); - this.descriptor = new ReferencedListDescriptorImpl(NamedResource.create(SUBJECT), ListHandlerTestBase.HAS_LIST, - ListHandlerTestBase.HAS_NEXT, ListHandlerTestBase.HAS_CONTENT); + this.descriptor = new ReferencedListDescriptorImpl(NamedResource.create(SUBJECT), ListTestHelper.HAS_LIST, + ListTestHelper.HAS_NEXT, ListTestHelper.HAS_CONTENT); this.iterator = iterator(); } @Override - OwlapiListIterator iterator() { - return new ReferencedListIterator(descriptor, snapshot, axiomAdapter); + OwlapiListIterator iterator() { + return new ReferencedListIterator<>(descriptor, snapshot, axiomAdapter); } } diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandlerTest.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandlerTest.java index 4061d5d2e..179389f17 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandlerTest.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListHandlerTest.java @@ -26,31 +26,71 @@ import cz.cvut.kbss.ontodriver.model.NamedResource; import cz.cvut.kbss.ontodriver.owlapi.OwlapiAdapter; import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot; +import cz.cvut.kbss.ontodriver.owlapi.environment.TestUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.semanticweb.owlapi.model.*; +import org.mockito.junit.jupiter.MockitoExtension; +import org.semanticweb.owlapi.model.AddAxiom; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLDataFactory; +import org.semanticweb.owlapi.model.OWLIndividual; +import org.semanticweb.owlapi.model.OWLNamedIndividual; +import org.semanticweb.owlapi.model.OWLObjectProperty; +import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyManager; +import org.semanticweb.owlapi.reasoner.OWLReasoner; import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNodeSet; import java.net.URI; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -public class SimpleListHandlerTest extends ListHandlerTestBase { +@ExtendWith(MockitoExtension.class) +public class SimpleListHandlerTest { + + OWLOntology ontology; + OWLOntologyManager manager; + OWLDataFactory dataFactory; + OWLNamedIndividual individual; + + @Mock + OWLReasoner reasonerMock; @Mock - private OwlapiAdapter adapterMock; + OwlapiAdapter adapterMock; + + SimpleListDescriptor descriptor; + SimpleListValueDescriptor valueDescriptor; + ListTestHelper testHelper; + + SimpleListHandler listHandler; @BeforeEach public void setUp() throws Exception { - MockitoAnnotations.openMocks(this); - super.setUp(); - this.descriptor = new SimpleListDescriptorImpl(SUBJECT, HAS_LIST, HAS_NEXT); + final OntologySnapshot realSnapshot = TestUtils.initRealOntology(reasonerMock); + this.ontology = spy(realSnapshot.getOntology()); + this.manager = spy(realSnapshot.getOntologyManager()); + this.dataFactory = realSnapshot.getDataFactory(); + this.individual = dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.SUBJECT.getIdentifier())); + this.descriptor = new SimpleListDescriptorImpl(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT); this.valueDescriptor = createDescriptor(); // This snapshot contains the spied on objects final OntologySnapshot snapshotToUse = new OntologySnapshot(ontology, manager, dataFactory, reasonerMock); @@ -58,9 +98,8 @@ public void setUp() throws Exception { this.testHelper = new SimpleListTestHelper(snapshotToUse, individual); } - @Override SimpleListValueDescriptor createDescriptor() { - return new SimpleListValueDescriptor(SUBJECT, HAS_LIST, HAS_NEXT); + return new SimpleListValueDescriptor(ListTestHelper.SUBJECT, ListTestHelper.HAS_LIST, ListTestHelper.HAS_NEXT); } @Test @@ -71,39 +110,39 @@ public void loadListReturnsEmptyListWhenNoListHeadIsFound() { @Test public void loadsListWithHeadOnly() { - final List list = LIST_ITEMS.subList(0, 1); + final List list = ListTestHelper.LIST_ITEMS.subList(0, 1); testHelper.persistList(list); final List> result = listHandler.loadList(descriptor); assertEquals(list.size(), result.size()); for (int i = 0; i < list.size(); i++) { - assertEquals(HAS_LIST, result.get(i).getAssertion()); + assertEquals(ListTestHelper.HAS_LIST, result.get(i).getAssertion()); assertEquals(list.get(i), result.get(i).getValue().getValue().getIdentifier()); } } @Test public void loadsListWithMultipleItems() { - testHelper.persistList(LIST_ITEMS); + testHelper.persistList(ListTestHelper.LIST_ITEMS); final List> result = listHandler.loadList(descriptor); - assertEquals(LIST_ITEMS.size(), result.size()); + assertEquals(ListTestHelper.LIST_ITEMS.size(), result.size()); verifyLoadedList(result); } private void verifyLoadedList(List> result) { - for (int i = 0; i < LIST_ITEMS.size(); i++) { + for (int i = 0; i < ListTestHelper.LIST_ITEMS.size(); i++) { if (i == 0) { - assertEquals(HAS_LIST, result.get(i).getAssertion()); + assertEquals(ListTestHelper.HAS_LIST, result.get(i).getAssertion()); } else { - assertEquals(HAS_NEXT, result.get(i).getAssertion()); + assertEquals(ListTestHelper.HAS_NEXT, result.get(i).getAssertion()); } - assertEquals(LIST_ITEMS.get(i), result.get(i).getValue().getValue().getIdentifier()); + assertEquals(ListTestHelper.LIST_ITEMS.get(i), result.get(i).getValue().getValue().getIdentifier()); } } @Test public void loadingListWithItemWithMultipleSuccessorsThrowsException() { - testHelper.persistList(LIST_ITEMS.subList(0, 5)); - addExtraSuccessor(LIST_ITEMS.get(2), LIST_ITEMS.get(8)); + testHelper.persistList(ListTestHelper.LIST_ITEMS.subList(0, 5)); + addExtraSuccessor(ListTestHelper.LIST_ITEMS.get(2), ListTestHelper.LIST_ITEMS.get(8)); assertThrows(IntegrityConstraintViolatedException.class, () -> listHandler.loadList(descriptor)); } @@ -117,36 +156,36 @@ private void addExtraSuccessor(URI target, URI successor) { @Test public void loadsListWithInferredProperties() { - initReasoner(LIST_ITEMS); - final SimpleListDescriptor infDescriptor = new SimpleListDescriptorImpl(SUBJECT, - Assertion.createObjectPropertyAssertion(HAS_LIST.getIdentifier(), true), - Assertion.createObjectPropertyAssertion(HAS_NEXT.getIdentifier(), true)); + initReasoner(); + final SimpleListDescriptor infDescriptor = new SimpleListDescriptorImpl(ListTestHelper.SUBJECT, + Assertion.createObjectPropertyAssertion(ListTestHelper.HAS_LIST.getIdentifier(), true), + Assertion.createObjectPropertyAssertion(ListTestHelper.HAS_NEXT.getIdentifier(), true)); final List> result = listHandler.loadList(infDescriptor); - assertEquals(LIST_ITEMS.size(), result.size()); + assertEquals(ListTestHelper.LIST_ITEMS.size(), result.size()); verifyLoadedList(result); verify(reasonerMock) - .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier())), - dataFactory.getOWLObjectProperty(IRI.create(HAS_LIST.getIdentifier()))); - verify(reasonerMock, times(LIST_ITEMS.size())) + .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.SUBJECT.getIdentifier())), + dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_LIST.getIdentifier()))); + verify(reasonerMock, times(ListTestHelper.LIST_ITEMS.size())) .getObjectPropertyValues(any(OWLNamedIndividual.class), - eq(dataFactory.getOWLObjectProperty(IRI.create(HAS_NEXT.getIdentifier())))); + eq(dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_NEXT.getIdentifier())))); } - private void initReasoner(List items) { - final OWLObjectProperty hasList = dataFactory.getOWLObjectProperty(IRI.create(HAS_LIST.getIdentifier())); - final OWLObjectProperty hasNext = dataFactory.getOWLObjectProperty(IRI.create(HAS_NEXT.getIdentifier())); + private void initReasoner() { + final OWLObjectProperty hasList = dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_LIST.getIdentifier())); + final OWLObjectProperty hasNext = dataFactory.getOWLObjectProperty(IRI.create(ListTestHelper.HAS_NEXT.getIdentifier())); when(reasonerMock - .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier())), + .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.SUBJECT.getIdentifier())), hasList)) - .thenReturn(new OWLNamedIndividualNodeSet(dataFactory.getOWLNamedIndividual(IRI.create(items.get(0))))); - for (int i = 1; i < items.size(); i++) { + .thenReturn(new OWLNamedIndividualNodeSet(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.LIST_ITEMS.get(0))))); + for (int i = 1; i < ListTestHelper.LIST_ITEMS.size(); i++) { when(reasonerMock - .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(items.get(i - 1))), hasNext)) + .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.LIST_ITEMS.get(i - 1))), hasNext)) .thenReturn( - new OWLNamedIndividualNodeSet(dataFactory.getOWLNamedIndividual(IRI.create(items.get(i))))); + new OWLNamedIndividualNodeSet(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.LIST_ITEMS.get(i))))); } when(reasonerMock - .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(items.get(items.size() - 1))), + .getObjectPropertyValues(dataFactory.getOWLNamedIndividual(IRI.create(ListTestHelper.LIST_ITEMS.get(ListTestHelper.LIST_ITEMS.size() - 1))), hasNext)).thenReturn(new OWLNamedIndividualNodeSet()); } @@ -159,7 +198,7 @@ public void persistEmptyListDoesNothing() { @Test public void persistListWithOneElementCreatesOnlyHead() { - valueDescriptor.addValue(NamedResource.create(LIST_ITEMS.get(0))); + valueDescriptor.addValue(NamedResource.create(ListTestHelper.LIST_ITEMS.get(0))); listHandler.persistList(valueDescriptor); final ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); @@ -170,39 +209,121 @@ public void persistListWithOneElementCreatesOnlyHead() { final OWLAxiom axiom = ax.getAxiom(); assertTrue(axiom instanceof OWLObjectPropertyAssertionAxiom); final OWLObjectProperty property = axiom.objectPropertiesInSignature().iterator().next(); - assertEquals(HAS_LIST.getIdentifier(), property.getIRI().toURI()); + assertEquals(ListTestHelper.HAS_LIST.getIdentifier(), property.getIRI().toURI()); final OWLIndividual value = ((OWLObjectPropertyAssertionAxiom) axiom).getObject(); - assertEquals(LIST_ITEMS.get(0), value.asOWLNamedIndividual().getIRI().toURI()); + assertEquals(ListTestHelper.LIST_ITEMS.get(0), value.asOWLNamedIndividual().getIRI().toURI()); verify(adapterMock).addTransactionalChanges(anyList()); } @Test public void persistNonEmptyListCreatesListInOntology() { - LIST_ITEMS.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + ListTestHelper.LIST_ITEMS.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); listHandler.persistList(valueDescriptor); final ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); verify(manager).applyChanges(captor.capture()); final List args = captor.getValue(); - assertEquals(LIST_ITEMS.size(), args.size()); + assertEquals(ListTestHelper.LIST_ITEMS.size(), args.size()); for (int i = 0; i < args.size(); i++) { final AddAxiom ax = (AddAxiom) args.get(i); final OWLAxiom axiom = ax.getAxiom(); assertTrue(axiom instanceof OWLObjectPropertyAssertionAxiom); final OWLObjectPropertyAssertionAxiom assertionAxiom = (OWLObjectPropertyAssertionAxiom) axiom; if (i == 0) { - assertEquals(SUBJECT.getIdentifier(), + assertEquals(ListTestHelper.SUBJECT.getIdentifier(), assertionAxiom.getSubject().asOWLNamedIndividual().getIRI().toURI()); - assertEquals(HAS_LIST.getIdentifier(), + assertEquals(ListTestHelper.HAS_LIST.getIdentifier(), assertionAxiom.getProperty().asOWLObjectProperty().getIRI().toURI()); } else { - assertEquals(LIST_ITEMS.get(i - 1), + assertEquals(ListTestHelper.LIST_ITEMS.get(i - 1), assertionAxiom.getSubject().asOWLNamedIndividual().getIRI().toURI()); - assertEquals(HAS_NEXT.getIdentifier(), + assertEquals(ListTestHelper.HAS_NEXT.getIdentifier(), assertionAxiom.getProperty().asOWLObjectProperty().getIRI().toURI()); } - assertEquals(LIST_ITEMS.get(i), assertionAxiom.getObject().asOWLNamedIndividual().getIRI().toURI()); + assertEquals(ListTestHelper.LIST_ITEMS.get(i), assertionAxiom.getObject().asOWLNamedIndividual().getIRI() + .toURI()); } verify(adapterMock).addTransactionalChanges(anyList()); } + + @Test + public void updateListToEmptyClearsList() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 5); + origList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + listHandler.persistList(valueDescriptor); + + final SimpleListValueDescriptor updatedDescriptor = createDescriptor(); + listHandler.updateList(updatedDescriptor); + + final List> result = listHandler.loadList(descriptor); + assertTrue(result.isEmpty()); + } + + @Test + public void updateEmptyListWithNonEmptyPersistsNewOne() { + final List updated = ListTestHelper.LIST_ITEMS.subList(0, 5); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByRemovingElementsFromTheEnd() { + testHelper.persistList(ListTestHelper.LIST_ITEMS); + final List subList = ListTestHelper.LIST_ITEMS.subList(0, 5); + subList.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(subList, result); + } + + @Test + public void updateListByReplacingSomeElementsButKeepingSize() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + + final List updated = new ArrayList<>(origList); + updated.set(2, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(4, ListTestHelper.LIST_ITEMS.get(9)); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByReplacingSomeElementsAndAddingNewOnes() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + final List updated = new ArrayList<>(origList); + updated.set(2, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(3, ListTestHelper.LIST_ITEMS.get(8)); + updated.add(ListTestHelper.LIST_ITEMS.get(9)); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } + + @Test + public void updateListByReplacingSomeElementsAndRemovingSome() { + final List origList = ListTestHelper.LIST_ITEMS.subList(0, 6); + testHelper.persistList(origList); + final List updated = new ArrayList<>(origList); + updated.set(0, ListTestHelper.LIST_ITEMS.get(7)); + updated.set(1, ListTestHelper.LIST_ITEMS.get(8)); + updated.remove(updated.size() - 1); + updated.remove(updated.size() - 2); + updated.forEach(item -> valueDescriptor.addValue(NamedResource.create(item))); + + listHandler.updateList(valueDescriptor); + final List> result = listHandler.loadList(descriptor); + ListTestHelper.verifyListContent(updated, result); + } } diff --git a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIteratorTest.java b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIteratorTest.java index c33ed8f7c..bc1086f4b 100644 --- a/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIteratorTest.java +++ b/ontodriver-owlapi/src/test/java/cz/cvut/kbss/ontodriver/owlapi/list/SimpleListIteratorTest.java @@ -33,13 +33,13 @@ public void setUp() throws Exception { super.setUp(); final OWLNamedIndividual individual = snapshot.getDataFactory().getOWLNamedIndividual(IRI.create(SUBJECT)); this.testHelper = new SimpleListTestHelper(snapshot, individual); - this.descriptor = new SimpleListDescriptorImpl(NamedResource.create(SUBJECT), ListHandlerTestBase.HAS_LIST, - ListHandlerTestBase.HAS_NEXT); + this.descriptor = new SimpleListDescriptorImpl(NamedResource.create(SUBJECT), ListTestHelper.HAS_LIST, + ListTestHelper.HAS_NEXT); this.iterator = iterator(); } @Override - protected OwlapiListIterator iterator() { + protected OwlapiListIterator iterator() { return new SimpleListIterator(descriptor, snapshot, axiomAdapter); } }