Skip to contentMethod: registerObserver(Observer)
1: /**
2: * Copyright (C) 2016 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.owlapi.query;
16:
17: import cz.cvut.kbss.ontodriver.Statement;
18: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
19: import cz.cvut.kbss.ontodriver.owlapi.exception.BindingValueMismatchException;
20: import cz.cvut.kbss.ontodriver.owlapi.exception.OwlapiDriverException;
21: import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils;
22: import cz.cvut.kbss.owl2query.model.GroundTerm;
23: import cz.cvut.kbss.owl2query.model.QueryResult;
24: import cz.cvut.kbss.owl2query.model.ResultBinding;
25: import cz.cvut.kbss.owl2query.model.Variable;
26: import org.semanticweb.owlapi.model.OWLEntity;
27: import org.semanticweb.owlapi.model.OWLLiteral;
28: import org.semanticweb.owlapi.model.OWLObject;
29:
30: import java.lang.reflect.Constructor;
31: import java.lang.reflect.InvocationTargetException;
32: import java.net.URI;
33: import java.util.*;
34:
35: import static cz.cvut.kbss.ontodriver.util.ErrorUtils.npxMessage;
36:
37: class SelectResultSet extends AbstractResultSet {
38:
39: private final QueryResult<OWLObject> queryResult;
40: private Iterator<ResultBinding<OWLObject>> iterator;
41:
42: private final Map<String, Variable<OWLObject>> namesToVariables;
43: private final Map<Integer, Variable<OWLObject>> indexesToVariables;
44:
45: private int currentIndex;
46: private ResultBinding<OWLObject> currentRow;
47:
48: public SelectResultSet(QueryResult<OWLObject> queryResult, Statement statement) {
49: super(statement);
50: this.queryResult = queryResult;
51: this.iterator = queryResult.iterator();
52: this.currentIndex = -1;
53: final int bindingSize = queryResult.getResultVars().size();
54: this.namesToVariables = new HashMap<>(bindingSize);
55: this.indexesToVariables = new HashMap<>(bindingSize);
56: resolveVariableNamesAndIndexes();
57: }
58:
59: private void resolveVariableNamesAndIndexes() {
60: Integer i = 0;
61: for (Variable<OWLObject> v : queryResult.getResultVars()) {
62: namesToVariables.put(v.getName(), v);
63: indexesToVariables.put(i, v);
64: i++;
65: }
66: }
67:
68: @Override
69: public int findColumn(String columnLabel) {
70: ensureOpen();
71: final Variable<OWLObject> v = namesToVariables.get(columnLabel);
72: if (v == null) {
73: return -1;
74: }
75: for (Map.Entry<Integer, Variable<OWLObject>> e : indexesToVariables.entrySet()) {
76: if (e.getValue().equals(v)) {
77: return e.getKey();
78: }
79: }
80: return -1;
81: }
82:
83: @Override
84: public int getColumnCount() {
85: ensureOpen();
86: return namesToVariables.size();
87: }
88:
89: @Override
90: public void first() throws OntoDriverException {
91: ensureOpen();
92: this.currentIndex = -1;
93: this.iterator = queryResult.iterator();
94: next();
95: }
96:
97: @Override
98: public boolean getBoolean(int columnIndex) throws OntoDriverException {
99: return getPrimitiveValue(Boolean.class, columnIndex);
100: }
101:
102: private <T> T getPrimitiveValue(Class<T> cls, int columnIndex) throws OntoDriverException {
103: final Object val = OwlapiUtils.owlLiteralToValue(getLiteral(columnIndex));
104: if (!cls.isAssignableFrom(val.getClass())) {
105: throw new BindingValueMismatchException("Value " + val + " cannot be returned as " + cls.getSimpleName());
106: }
107: return cls.cast(val);
108: }
109:
110: private OWLLiteral getLiteral(int columnIndex) throws OntoDriverException {
111: final OWLObject currentValue = getCurrentValue(columnIndex);
112: if (!(currentValue instanceof OWLLiteral)) {
113: throw new BindingValueMismatchException("Value " + currentValue + " is not an OWLLiteral.");
114: }
115: return (OWLLiteral) currentValue;
116: }
117:
118: private OWLObject getCurrentValue(int columnIndex) throws OntoDriverException {
119: ensureOpen();
120: if (currentRow == null) {
121: throw new IllegalStateException("Current row is null.");
122: }
123: if (!indexesToVariables.containsKey(columnIndex)) {
124: throw new OntoDriverException("No result binding found for index " + columnIndex);
125: }
126: final Variable<OWLObject> v = indexesToVariables.get(columnIndex);
127: final GroundTerm<OWLObject> gt = currentRow.get(v);
128: return gt != null ? gt.getWrappedObject() : null;
129: }
130:
131: @Override
132: public boolean getBoolean(String columnLabel) throws OntoDriverException {
133: return getPrimitiveValue(Boolean.class, columnLabel);
134: }
135:
136: private <T> T getPrimitiveValue(Class<T> cls, String columnLabel) throws OwlapiDriverException {
137: final Object val = OwlapiUtils.owlLiteralToValue(getLiteral(columnLabel));
138: if (!cls.isAssignableFrom(val.getClass())) {
139: throw new BindingValueMismatchException("Value " + val + " cannot be returned as " + cls.getSimpleName());
140: }
141: return cls.cast(val);
142: }
143:
144: private OWLLiteral getLiteral(String columnLabel) throws OwlapiDriverException {
145: final OWLObject currentValue = getCurrentValue(columnLabel);
146: if (!(currentValue instanceof OWLLiteral)) {
147: throw new BindingValueMismatchException("Value " + currentValue + " is not an OWLLiteral.");
148: }
149: return (OWLLiteral) currentValue;
150: }
151:
152: private OWLObject getCurrentValue(String columnLabel) throws OwlapiDriverException {
153: ensureOpen();
154: if (currentRow == null) {
155: throw new IllegalStateException("Current row is null.");
156: }
157: if (!namesToVariables.containsKey(columnLabel)) {
158: throw new OwlapiDriverException("No result binding found for label " + columnLabel);
159: }
160: final Variable<OWLObject> v = namesToVariables.get(columnLabel);
161: final GroundTerm<OWLObject> gt = currentRow.get(v);
162: return gt != null ? gt.getWrappedObject() : null;
163: }
164:
165: @Override
166: public byte getByte(int columnIndex) throws OntoDriverException {
167: final Number num = getPrimitiveValue(Number.class, columnIndex);
168: return num.byteValue();
169: }
170:
171: @Override
172: public byte getByte(String columnLabel) throws OntoDriverException {
173: final Number num = getPrimitiveValue(Number.class, columnLabel);
174: return num.byteValue();
175: }
176:
177: @Override
178: public double getDouble(int columnIndex) throws OntoDriverException {
179: final Number num = getPrimitiveValue(Number.class, columnIndex);
180: return num.doubleValue();
181: }
182:
183: @Override
184: public double getDouble(String columnLabel) throws OntoDriverException {
185: final Number num = getPrimitiveValue(Number.class, columnLabel);
186: return num.doubleValue();
187: }
188:
189: @Override
190: public float getFloat(int columnIndex) throws OntoDriverException {
191: final Number num = getPrimitiveValue(Number.class, columnIndex);
192: return num.floatValue();
193: }
194:
195: @Override
196: public float getFloat(String columnLabel) throws OntoDriverException {
197: final Number num = getPrimitiveValue(Number.class, columnLabel);
198: return num.floatValue();
199: }
200:
201: @Override
202: public int getInt(int columnIndex) throws OntoDriverException {
203: final Number num = getPrimitiveValue(Number.class, columnIndex);
204: return num.intValue();
205: }
206:
207: @Override
208: public int getInt(String columnLabel) throws OntoDriverException {
209: final Number num = getPrimitiveValue(Number.class, columnLabel);
210: return num.intValue();
211: }
212:
213: @Override
214: public long getLong(int columnIndex) throws OntoDriverException {
215: final Number num = getPrimitiveValue(Number.class, columnIndex);
216: return num.longValue();
217: }
218:
219: @Override
220: public long getLong(String columnLabel) throws OntoDriverException {
221: final Number num = getPrimitiveValue(Number.class, columnLabel);
222: return num.longValue();
223: }
224:
225: @Override
226: public Object getObject(int columnIndex) throws OntoDriverException {
227: return owlObjectToObject(getCurrentValue(columnIndex));
228: }
229:
230: private Object owlObjectToObject(OWLObject owlValue) {
231: if (owlValue == null) {
232: return null;
233: }
234: if (owlValue instanceof OWLLiteral) {
235: return OwlapiUtils.owlLiteralToValue((OWLLiteral) owlValue);
236: }
237: final Set<OWLEntity> sig = owlValue.getSignature();
238: if (sig.isEmpty()) {
239: return owlValue.toString();
240: } else {
241: return URI.create(sig.iterator().next().toStringID());
242: }
243: }
244:
245: @Override
246: public Object getObject(String columnLabel) throws OntoDriverException {
247: return owlObjectToObject(getCurrentValue(columnLabel));
248: }
249:
250: @Override
251: public <T> T getObject(int columnIndex, Class<T> cls) throws OntoDriverException {
252: Objects.requireNonNull(cls, npxMessage("cls"));
253: return owlObjectToType(getCurrentValue(columnIndex), cls);
254: }
255:
256: private <T> T owlObjectToType(OWLObject owlValue, Class<T> cls) throws OntoDriverException {
257: if (cls.isAssignableFrom(owlValue.getClass())) {
258: return cls.cast(owlValue);
259: }
260: if (owlValue instanceof OWLLiteral) {
261: final Object ob = OwlapiUtils.owlLiteralToValue((OWLLiteral) owlValue);
262: if (cls.isAssignableFrom(ob.getClass())) {
263: return cls.cast(ob);
264: }
265: } else {
266: final Set<OWLEntity> sig = owlValue.getSignature();
267: if (!sig.isEmpty()) {
268: final URI uri = URI.create(sig.iterator().next().toStringID());
269: if (cls.isAssignableFrom(uri.getClass())) {
270: return cls.cast(uri);
271: }
272: return tryInstantiatingClassUsingConstructor(cls, uri);
273: }
274: }
275: throw new OwlapiDriverException("Conversion to type " + cls + " is not supported.");
276: }
277:
278: private <T> T tryInstantiatingClassUsingConstructor(Class<T> cls, URI uri) throws OwlapiDriverException {
279: try {
280: final Constructor<T> constructor = cls.getDeclaredConstructor(uri.getClass());
281: if (!constructor.isAccessible()) {
282: constructor.setAccessible(true);
283: }
284: return constructor.newInstance(uri);
285: } catch (NoSuchMethodException e) {
286: throw new OwlapiDriverException(
287: "No constructor taking parameter of type " + uri.getClass().getName() + " found in class " + cls,
288: e);
289: } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
290: throw new OwlapiDriverException(
291: "Unable to create instance of class " + cls + " using constructor with argument " + uri, e);
292: }
293: }
294:
295: @Override
296: public <T> T getObject(String columnLabel, Class<T> cls) throws OntoDriverException {
297: Objects.requireNonNull(cls, npxMessage("cls"));
298: return owlObjectToType(getCurrentValue(columnLabel), cls);
299: }
300:
301: @Override
302: public int getRowIndex() throws OntoDriverException {
303: return currentIndex;
304: }
305:
306: @Override
307: public short getShort(int columnIndex) throws OntoDriverException {
308: final Number num = getPrimitiveValue(Number.class, columnIndex);
309: return num.shortValue();
310: }
311:
312: @Override
313: public short getShort(String columnLabel) throws OntoDriverException {
314: final Number num = getPrimitiveValue(Number.class, columnLabel);
315: return num.shortValue();
316: }
317:
318: @Override
319: public String getString(int columnIndex) throws OntoDriverException {
320: return owlValueToString(getCurrentValue(columnIndex));
321: }
322:
323: private String owlValueToString(OWLObject owlValue) {
324: if (owlValue instanceof OWLLiteral) {
325: return OwlapiUtils.owlLiteralToValue((OWLLiteral) owlValue).toString();
326: }
327: final Set<OWLEntity> sig = owlValue.getSignature();
328: if (sig.isEmpty()) {
329: return owlValue.toString();
330: } else {
331: return sig.iterator().next().toStringID();
332: }
333: }
334:
335: @Override
336: public String getString(String columnLabel) throws OntoDriverException {
337: return owlValueToString(getCurrentValue(columnLabel));
338: }
339:
340: @Override
341: public boolean isFirst() throws OntoDriverException {
342: ensureOpen();
343: return currentIndex == 0;
344: }
345:
346: @Override
347: public boolean hasNext() throws OntoDriverException {
348: ensureOpen();
349: return iterator.hasNext();
350: }
351:
352: @Override
353: public void last() throws OntoDriverException {
354: ensureOpen();
355: while (hasNext()) {
356: next();
357: }
358: }
359:
360: @Override
361: public void next() throws OntoDriverException {
362: ensureOpen();
363: if (!hasNext()) {
364: throw new NoSuchElementException("The result set has no more rows.");
365: }
366: this.currentRow = iterator.next();
367: currentIndex++;
368: }
369:
370: @Override
371: public void previous() throws OntoDriverException {
372: ensureOpen();
373: relative(-1);
374: }
375:
376: @Override
377: public void registerObserver(Observer observer) throws OntoDriverException {
378: // Not implemented yet
379: }
380:
381: @Override
382: public void relative(int rows) throws OntoDriverException {
383: ensureOpen();
384: setRowIndex(currentIndex + rows);
385: }
386:
387: @Override
388: public void setRowIndex(int rowIndex) throws OntoDriverException {
389: ensureOpen();
390: if (rowIndex == currentIndex) {
391: return;
392: }
393: if (rowIndex < 0) {
394: throw new IllegalArgumentException("Cannot set row index to a number less than 0.");
395: }
396: if (rowIndex < currentIndex) {
397: first();
398: }
399: while (rowIndex > currentIndex && hasNext()) {
400: next();
401: }
402: }
403: }