Skip to content

Method: hasNext(ListDescriptor)

1: /**
2: * Copyright (C) 2020 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.ontodriver.sesame;
16:
17: import cz.cvut.kbss.ontodriver.descriptor.*;
18: import cz.cvut.kbss.ontodriver.exception.IntegrityConstraintViolatedException;
19: import cz.cvut.kbss.ontodriver.model.Axiom;
20: import cz.cvut.kbss.ontodriver.model.NamedResource;
21: import cz.cvut.kbss.ontodriver.sesame.connector.Connector;
22: import cz.cvut.kbss.ontodriver.sesame.exceptions.SesameDriverException;
23: import cz.cvut.kbss.ontodriver.sesame.util.SesameUtils;
24: import org.eclipse.rdf4j.model.*;
25:
26: import java.util.ArrayList;
27: import java.util.Collection;
28: import java.util.List;
29:
30: /**
31: * Base class for list handlers.
32: * <p>
33: * List handlers are responsible for loading and persisting lists.
34: *
35: * @param <T> List descriptor type
36: * @param <V> List value descriptor type
37: */
38: abstract class ListHandler<T extends ListDescriptor, V extends ListValueDescriptor> {
39:
40: protected final Connector connector;
41: protected final ValueFactory vf;
42:
43: ListHandler(Connector connector, ValueFactory vf) {
44: this.connector = connector;
45: this.vf = vf;
46: }
47:
48: /**
49: * Loads axioms representing list described by the specified list
50: * descriptor.
51: *
52: * @return Collection of axioms representing sequence values
53: * @throws SesameDriverException When storage access error occurs
54: */
55: List<Axiom<NamedResource>> loadList(T listDescriptor) throws SesameDriverException {
56: final List<Axiom<NamedResource>> axioms = new ArrayList<>();
57: final SesameIterator it = createIterator(listDescriptor);
58: while (it.hasNext()) {
59: axioms.add(it.nextAxiom());
60: }
61: return axioms;
62: }
63:
64: abstract SesameIterator createIterator(T listDescriptor) throws SesameDriverException;
65:
66: /**
67: * Persists list values specified by the descriptor.
68: * <p>
69: * The values are saved in the order in which they appear in the descriptor.
70: *
71: * @param listValueDescriptor Describes values to persist
72: * @throws SesameDriverException When storage access error occurs
73: */
74: void persistList(V listValueDescriptor) throws SesameDriverException {
75: if (listValueDescriptor.getValues().isEmpty()) {
76: return;
77: }
78: final Collection<Statement> statements = new ArrayList<>(listValueDescriptor.getValues()
79: .size());
80: final IRI head = createListHead(listValueDescriptor, statements);
81: statements.addAll(createListRest(head, listValueDescriptor));
82: connector.addStatements(statements);
83: }
84:
85: abstract IRI createListHead(V valueDescriptor, Collection<Statement> listStatements) throws SesameDriverException;
86:
87: abstract List<Statement> createListRest(IRI head, V valueDescriptor) throws SesameDriverException;
88:
89: /**
90: * Updates list with values specified by the descriptor.
91: *
92: * @param listValueDescriptor Describes the updated values
93: * @throws SesameDriverException When storage access error occurs
94: */
95: void updateList(V listValueDescriptor) throws SesameDriverException {
96: if (listValueDescriptor.getValues().isEmpty()) {
97: clearList(listValueDescriptor);
98: } else if (isOldListEmpty(owner(listValueDescriptor), hasList(listValueDescriptor),
99: listValueDescriptor.getListProperty().isInferred(), context(listValueDescriptor))) {
100: persistList(listValueDescriptor);
101: } else {
102: mergeList(listValueDescriptor);
103: }
104: }
105:
106: private boolean isOldListEmpty(Resource owner, IRI hasListProperty, boolean includeInferred,
107: IRI context) throws SesameDriverException {
108: final Collection<Statement> stmts = connector.findStatements(owner, hasListProperty, null,
109: includeInferred, context);
110: return stmts.isEmpty();
111: }
112:
113: abstract void clearList(V listDescriptor) throws SesameDriverException;
114:
115: private void mergeList(V listDescriptor) throws SesameDriverException {
116: final SesameIterator it = iterator(listDescriptor);
117: final MergeResult mergeResult = mergeWithOriginalList(listDescriptor, it);
118: removeObsoletes(it);
119: assert mergeResult.i > 0;
120: assert mergeResult.previous != null;
121: if (mergeResult.i < listDescriptor.getValues().size()) {
122: appendNewNodes(listDescriptor, mergeResult);
123: }
124: }
125:
126: abstract SesameIterator iterator(V listDescriptor) throws SesameDriverException;
127:
128: abstract MergeResult mergeWithOriginalList(V listDescriptor, SesameIterator it) throws SesameDriverException;
129:
130: abstract void appendNewNodes(V listDescriptor, MergeResult mergeResult) throws SesameDriverException;
131:
132: private void removeObsoletes(SesameIterator it) throws SesameDriverException {
133: while (it.hasNext()) {
134: it.nextNode();
135: it.remove();
136: }
137: }
138:
139: Resource extractListNode(Collection<Statement> stmts, IRI nodeAssertion) {
140: if (stmts.size() > 1) {
141: throw new IntegrityConstraintViolatedException(
142: "Invalid number of values found for assertion " + nodeAssertion + ". Expected 1, got " +
143: stmts.size());
144: }
145: final Value val = stmts.iterator().next().getObject();
146: if (!(val instanceof Resource)) {
147: throw new IntegrityConstraintViolatedException(
148: "Invalid property value. Expected object property value, got literal.");
149: }
150: return (Resource) val;
151: }
152:
153: IRI context(ListDescriptor listDescriptor) {
154: return sesameIri(listDescriptor.getContext());
155: }
156:
157: IRI owner(ListDescriptor listDescriptor) {
158: return sesameIri(listDescriptor.getListOwner().getIdentifier());
159: }
160:
161: IRI hasList(ListDescriptor listDescriptor) {
162: return sesameIri(listDescriptor.getListProperty().getIdentifier());
163: }
164:
165: IRI hasNext(ListDescriptor listDescriptor) {
166: return sesameIri(listDescriptor.getNextNode().getIdentifier());
167: }
168:
169: IRI sesameIri(java.net.URI uri) {
170: return SesameUtils.toSesameIri(uri, vf);
171: }
172:
173: /**
174: * Creates handler for simple lists.
175: *
176: * @param connector Storage connector
177: * @param vf Sesame value factory
178: * @return List handler
179: */
180: static ListHandler<SimpleListDescriptor, SimpleListValueDescriptor> createForSimpleList(
181: Connector connector, ValueFactory vf) {
182: assert connector != null;
183: assert vf != null;
184:
185: return new SimpleListHandler(connector, vf);
186: }
187:
188: /**
189: * Creates handler for referenced lists.
190: *
191: * @param connector Storage connector
192: * @param vf Sesame value factory
193: * @return List handler
194: */
195: static ListHandler<ReferencedListDescriptor, ReferencedListValueDescriptor> createForReferencedList(
196: Connector connector, ValueFactory vf) {
197: assert connector != null;
198: assert vf != null;
199:
200: return new ReferencedListHandler(connector, vf);
201: }
202:
203: static final class MergeResult {
204: protected int i;
205: Resource previous;
206:
207: MergeResult(int i, Resource node) {
208: this.i = i;
209: this.previous = node;
210: }
211: }
212: }