Skip to content

Method: hasNext()

1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.ontodriver.rdf4j.list;
19:
20: import cz.cvut.kbss.ontodriver.descriptor.ReferencedListDescriptor;
21: import cz.cvut.kbss.ontodriver.exception.IntegrityConstraintViolatedException;
22: import cz.cvut.kbss.ontodriver.model.Axiom;
23: import cz.cvut.kbss.ontodriver.model.AxiomImpl;
24: import cz.cvut.kbss.ontodriver.model.MultilingualString;
25: import cz.cvut.kbss.ontodriver.model.NamedResource;
26: import cz.cvut.kbss.ontodriver.model.Value;
27: import cz.cvut.kbss.ontodriver.rdf4j.connector.RepoConnection;
28: import cz.cvut.kbss.ontodriver.rdf4j.exception.Rdf4jDriverException;
29: import cz.cvut.kbss.ontodriver.rdf4j.util.Rdf4jUtils;
30: import org.eclipse.rdf4j.model.IRI;
31: import org.eclipse.rdf4j.model.Literal;
32: import org.eclipse.rdf4j.model.Resource;
33: import org.eclipse.rdf4j.model.Statement;
34: import org.eclipse.rdf4j.model.ValueFactory;
35: import org.eclipse.rdf4j.model.vocabulary.RDF;
36:
37: import java.util.ArrayList;
38: import java.util.Collection;
39: import java.util.Collections;
40: import java.util.HashSet;
41: import java.util.Set;
42: import java.util.stream.Collectors;
43:
44: class ReferencedListIterator<T> extends AbstractListIterator<T> {
45:
46: private final ReferencedListDescriptor listDescriptor;
47:
48: private final IRI hasContentProperty;
49:
50: private IRI currentProperty;
51:
52: private Statement currentNode;
53: private Collection<Statement> currentContent;
54: private Collection<Statement> next;
55:
56: public ReferencedListIterator(ReferencedListDescriptor listDescriptor, RepoConnection connector, ValueFactory vf)
57: throws Rdf4jDriverException {
58: super(listDescriptor, connector, vf);
59: this.listDescriptor = listDescriptor;
60: this.hasContentProperty = Rdf4jUtils.toRdf4jIri(listDescriptor.getNodeContent().getIdentifier(), vf);
61: this.currentProperty = hasListProperty;
62: init();
63: }
64:
65: private void init() throws Rdf4jDriverException {
66: this.next = connector.findStatements(listOwner, hasListProperty, null, includeInferred, contexts());
67: }
68:
69: @Override
70: public boolean hasNext() {
71:• return !next.isEmpty() && !isNextNil();
72: }
73:
74: private boolean isNextNil() {
75: assert next != null;
76: return RDF.NIL.equals(next.iterator().next().getObject());
77: }
78:
79: @Override
80: public Resource nextNode() throws Rdf4jDriverException {
81: nextInternal();
82: return (Resource) currentNode.getObject();
83: }
84:
85: private void nextInternal() throws Rdf4jDriverException {
86: if (!hasNext()) {
87: throw new IllegalStateException();
88: }
89: super.checkSuccessorMax(next, currentProperty);
90: this.currentNode = next.iterator().next();
91: this.currentProperty = currentNode.getPredicate();
92: checkObjectIsResource(currentNode);
93: final Resource elem = (Resource) currentNode.getObject();
94: this.currentContent = getNodeContent(elem);
95: this.next = connector.findStatements(elem, hasNextProperty, null, includeInferred, contexts());
96: }
97:
98: private Collection<Statement> getNodeContent(Resource node) throws Rdf4jDriverException {
99: final Collection<Statement> elements = connector.findStatements(node, hasContentProperty,
100: null, includeInferred, contexts());
101: checkSuccessorMax(elements, hasContentProperty);
102: if (elements.isEmpty()) {
103: throw new IntegrityConstraintViolatedException("Node " + node + " has no content.");
104: }
105: return elements;
106: }
107:
108: @Override
109: protected void checkSuccessorMax(Collection<Statement> stmts, IRI property) {
110: final Set<String> langs = new HashSet<>();
111: // Remove duplicates
112: final Set<Statement> statements = new HashSet<>(stmts);
113: if (statements.size() == 1) {
114: return;
115: }
116: for (Statement s : statements) {
117: if (!s.getObject().isLiteral()) {
118: throw icViolatedException(property, statements.size());
119: }
120: final Literal literal = (Literal) s.getObject();
121: if (literal.getLanguage().isPresent() && !langs.contains(literal.getLanguage().get())) {
122: langs.add(literal.getLanguage().get());
123: } else {
124: throw icViolatedException(property, statements.size());
125: }
126: }
127: }
128:
129: @Override
130: public T currentContent() {
131: if (currentContent.size() == 1) {
132: return (T) fromRdf4jValue(currentContent.iterator().next().getObject());
133: } else {
134: final MultilingualString mls = currentContentToMultilingualString();
135: return (T) mls;
136: }
137: }
138:
139: private static Object fromRdf4jValue(org.eclipse.rdf4j.model.Value value) {
140: return value.isLiteral() ? Rdf4jUtils.getLiteralValue((Literal) value) : NamedResource.create(value.stringValue());
141: }
142:
143: @Override
144: public Axiom<T> nextAxiom() throws Rdf4jDriverException {
145: nextInternal();
146:
147: if (currentContent.size() == 1) {
148: final org.eclipse.rdf4j.model.Value obj = currentContent.iterator().next().getObject();
149: return new AxiomImpl(NamedResource.create(currentContent.iterator().next().getSubject().stringValue()),
150: listDescriptor.getNodeContent(),
151: new Value<>(fromRdf4jValue(obj)));
152: }
153: final MultilingualString mls = currentContentToMultilingualString();
154: return new AxiomImpl(NamedResource.create(currentContent.iterator().next().getSubject().stringValue()),
155: listDescriptor.getNodeContent(), new Value<>(mls));
156: }
157:
158: private MultilingualString currentContentToMultilingualString() {
159: final MultilingualString mls = new MultilingualString();
160: currentContent.forEach(s -> {
161: assert s.getObject().isLiteral();
162: final Literal literal = (Literal) s.getObject();
163: assert literal.getLanguage().isPresent();
164: mls.set(literal.getLanguage().get(), literal.getLabel());
165: });
166: return mls;
167: }
168:
169: @Override
170: public void remove() throws Rdf4jDriverException {
171: assert currentNode.getObject() instanceof Resource;
172: final Collection<Statement> toRemove = new ArrayList<>();
173: toRemove.add(currentNode);
174: toRemove.addAll(currentContent);
175: if (!next.isEmpty()) {
176: toRemove.addAll(next);
177: final Statement stmt = next.iterator().next();
178: checkObjectIsResource(stmt);
179: final Resource nextNode = (Resource) stmt.getObject();
180: final Statement connectNext = vf
181: .createStatement(currentNode.getSubject(), currentProperty, nextNode, context);
182: this.next = Collections.singleton(connectNext);
183:
184: this.currentNode = null;
185: this.currentContent = null;
186: connector.addStatements(next);
187: } else {
188: next = Collections.emptyList();
189: }
190: connector.removeStatements(toRemove);
191: }
192:
193: @Override
194: public void replaceCurrentWith(T newContent) throws Rdf4jDriverException {
195: assert currentNode.getObject() instanceof Resource;
196: // We just replace the original content statement with new one
197: connector.removeStatements(currentContent);
198: final Collection<org.eclipse.rdf4j.model.Value> contentValues = new ReferencedListHelper(valueConverter).toRdf4jValue(listDescriptor.getNodeContent(), newContent);
199: final Resource node = (Resource) currentNode.getObject();
200: connector.addStatements(contentValues.stream()
201: .map(v -> vf.createStatement(node, hasContentProperty, v, context))
202: .collect(Collectors.toList()));
203: }
204: }