Skip to contentMethod: toDouble(Object)
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.query;
16:
17: import cz.cvut.kbss.ontodriver.Statement;
18: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
19: import cz.cvut.kbss.ontodriver.exception.VariableNotBoundException;
20: import cz.cvut.kbss.ontodriver.sesame.exceptions.SesameDriverException;
21: import cz.cvut.kbss.ontodriver.sesame.util.SesameUtils;
22: import org.eclipse.rdf4j.model.IRI;
23: import org.eclipse.rdf4j.model.Literal;
24: import org.eclipse.rdf4j.model.Value;
25: import org.eclipse.rdf4j.query.BindingSet;
26: import org.eclipse.rdf4j.query.QueryEvaluationException;
27: import org.eclipse.rdf4j.query.TupleQueryResult;
28:
29: import java.lang.reflect.Constructor;
30: import java.lang.reflect.InvocationTargetException;
31: import java.util.List;
32: import java.util.Objects;
33:
34: // TODO Resolve mapping of data values with language tag
35: public class SelectResultSet extends AbstractResultSet {
36:
37: private final TupleQueryResult result;
38: private List<String> bindings;
39: private BindingSet current;
40:
41: public SelectResultSet(TupleQueryResult result, Statement statement) {
42: super(statement);
43: assert result != null;
44:
45: this.result = result;
46: init();
47: }
48:
49: private void init() {
50: this.bindings = result.getBindingNames();
51: }
52:
53: @Override
54: public void close() throws OntoDriverException {
55: try {
56: result.close();
57: } catch (QueryEvaluationException e) {
58: throw new OntoDriverException(e);
59: } finally {
60: super.close();
61: }
62: }
63:
64: @Override
65: public int findColumn(String columnLabel) {
66: ensureOpen();
67: return bindings.indexOf(columnLabel);
68: }
69:
70: @Override
71: public int getColumnCount() {
72: ensureOpen();
73: return bindings.size();
74: }
75:
76: @Override
77: public boolean isBound(int variableIndex) {
78: return variableIndex >= 0 && variableIndex < bindings.size() && current
79: .getValue(bindings.get(variableIndex)) != null;
80: }
81:
82: @Override
83: public boolean isBound(String variableName) {
84: Objects.requireNonNull(variableName);
85: return bindings.contains(variableName) && current.getValue(variableName) != null;
86: }
87:
88: @Override
89: public boolean getBoolean(int columnIndex) throws OntoDriverException {
90: ensureOpen();
91: return toBoolean(getLiteralValue(columnIndex));
92: }
93:
94: @Override
95: public boolean getBoolean(String columnLabel) throws OntoDriverException {
96: ensureOpen();
97: return toBoolean(getLiteralValue(columnLabel));
98: }
99:
100: private boolean toBoolean(Object ob) {
101: if (ob instanceof Boolean) {
102: return (boolean) ob;
103: } else {
104: return Boolean.parseBoolean(ob.toString());
105: }
106: }
107:
108: @Override
109: public byte getByte(int columnIndex) throws OntoDriverException {
110: ensureOpen();
111: return (byte) toInt(getLiteralValue(columnIndex));
112: }
113:
114: @Override
115: public byte getByte(String columnLabel) throws OntoDriverException {
116: ensureOpen();
117: return (byte) toInt(getLiteralValue(columnLabel));
118: }
119:
120: @Override
121: public double getDouble(int columnIndex) throws OntoDriverException {
122: ensureOpen();
123: return toDouble(getLiteralValue(columnIndex));
124: }
125:
126: @Override
127: public double getDouble(String columnLabel) throws OntoDriverException {
128: ensureOpen();
129: return toDouble(getLiteralValue(columnLabel));
130: }
131:
132: private double toDouble(Object ob) throws OntoDriverException {
133:• if (ob instanceof Number) {
134: return ((Number) ob).doubleValue();
135: } else {
136: try {
137: return Double.parseDouble(ob.toString());
138: } catch (NumberFormatException e) {
139: throw new OntoDriverException(e);
140: }
141: }
142: }
143:
144: @Override
145: public float getFloat(int columnIndex) throws OntoDriverException {
146: ensureOpen();
147: return toFloat(getLiteralValue(columnIndex));
148: }
149:
150: @Override
151: public float getFloat(String columnLabel) throws OntoDriverException {
152: ensureOpen();
153: return toFloat(getLiteralValue(columnLabel));
154: }
155:
156: private float toFloat(Object ob) throws OntoDriverException {
157: if (ob instanceof Number) {
158: return ((Number) ob).floatValue();
159: } else {
160: try {
161: return Float.parseFloat(ob.toString());
162: } catch (NumberFormatException e) {
163: throw new OntoDriverException(e);
164: }
165: }
166: }
167:
168: @Override
169: public int getInt(int columnIndex) throws OntoDriverException {
170: ensureOpen();
171: return toInt(getLiteralValue(columnIndex));
172: }
173:
174: @Override
175: public int getInt(String columnLabel) throws OntoDriverException {
176: ensureOpen();
177: return toInt(getLiteralValue(columnLabel));
178: }
179:
180: private int toInt(Object ob) throws OntoDriverException {
181: if (ob instanceof Number) {
182: return ((Number) ob).intValue();
183: } else {
184: try {
185: return Integer.parseInt(ob.toString());
186: } catch (NumberFormatException e) {
187: throw new OntoDriverException(e);
188: }
189: }
190: }
191:
192: @Override
193: public long getLong(int columnIndex) throws OntoDriverException {
194: ensureOpen();
195: return toLong(getLiteralValue(columnIndex));
196: }
197:
198: @Override
199: public long getLong(String columnLabel) throws OntoDriverException {
200: ensureOpen();
201: return toLong(getLiteralValue(columnLabel));
202: }
203:
204: private long toLong(Object ob) throws OntoDriverException {
205: if (ob instanceof Number) {
206: return ((Number) ob).longValue();
207: } else {
208: try {
209: return Long.parseLong(ob.toString());
210: } catch (NumberFormatException e) {
211: throw new OntoDriverException(e);
212: }
213: }
214: }
215:
216: @Override
217: public Object getObject(int columnIndex) {
218: ensureOpen();
219: return toObject(getCurrent(columnIndex));
220: }
221:
222: @Override
223: public Object getObject(String columnLabel) {
224: ensureOpen();
225: return toObject(getCurrent(columnLabel));
226: }
227:
228: private Object toObject(Value val) {
229: assert val != null;
230: if (val instanceof Literal) {
231: return SesameUtils.getDataPropertyValue((Literal) val);
232: } else if (val instanceof IRI) {
233: return SesameUtils.toJavaUri((IRI) val);
234: } else {
235: return val.toString();
236: }
237: }
238:
239: @Override
240: public <T> T getObject(int columnIndex, Class<T> cls) throws OntoDriverException {
241: ensureOpen();
242: return toObject(getCurrent(columnIndex), cls);
243: }
244:
245: @Override
246: public <T> T getObject(String columnLabel, Class<T> cls) throws OntoDriverException {
247: ensureOpen();
248: return toObject(getCurrent(columnLabel), cls);
249: }
250:
251: private <T> T toObject(Value val, Class<T> cls) throws OntoDriverException {
252: assert val != null;
253: if (cls.isAssignableFrom(val.getClass())) {
254: return cls.cast(val);
255: }
256: Object ob = null;
257: if (val instanceof Literal) {
258: ob = SesameUtils.getDataPropertyValue((Literal) val);
259: } else if (val instanceof IRI) {
260: ob = SesameUtils.toJavaUri((IRI) val);
261: }
262: if (ob != null && cls.isAssignableFrom(ob.getClass())) {
263: return cls.cast(ob);
264: }
265: ob = val;
266: return instantiateUsingConstructor(cls, val, ob);
267: }
268:
269: /**
270: * Searches for a suitable constructor and creates a new instance of class {@code cls}. </p>
271: * <p>
272: * The type has to have single-argument constructor, which takes either {@code Value} or its subtypes or type of
273: * instance returned by {@link SesameUtils#getDataPropertyValue(Literal)}.
274: *
275: * @param cls The return type
276: * @param val Raw value
277: * @param ob Either raw value (if it is a resource) or instance returned by {@link
278: * SesameUtils#getDataPropertyValue(Literal)} on passing the literal {@code val}
279: * @return The new instance
280: * @throws OntoDriverException If no suitable constructor is found or the instance cannot be created
281: */
282: private <T> T instantiateUsingConstructor(Class<T> cls, Value val, Object ob)
283: throws OntoDriverException {
284: Constructor<?>[] ctors = cls.getDeclaredConstructors();
285: try {
286: for (Constructor<?> c : ctors) {
287: if (c.getParameterTypes().length != 1) {
288: continue;
289: }
290: c.setAccessible(true);
291: final Class<?> type = c.getParameterTypes()[0];
292: if (type.isAssignableFrom(ob.getClass())) {
293: return cls.cast(c.newInstance(ob));
294: }
295: if (type.isAssignableFrom(val.getClass())) {
296: return cls.cast(c.newInstance(val));
297: }
298: if (type.isAssignableFrom(String.class)) {
299: return cls.cast(c.newInstance(ob.toString()));
300: }
301: }
302: } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
303: | InvocationTargetException e) {
304: throw new SesameDriverException("Unable to create instance of type " + cls + " with value " + val, e);
305: }
306: throw new SesameDriverException("No suitable constructor for value " + val + " found in type " + cls);
307: }
308:
309: @Override
310: public short getShort(int columnIndex) throws OntoDriverException {
311: ensureOpen();
312: return (short) toInt(getLiteralValue(columnIndex));
313: }
314:
315: @Override
316: public short getShort(String columnLabel) throws OntoDriverException {
317: ensureOpen();
318: return (short) toInt(getLiteralValue(columnLabel));
319: }
320:
321: @Override
322: public String getString(int columnIndex) {
323: ensureOpen();
324: return getStringImpl(getCurrent(columnIndex));
325: }
326:
327: @Override
328: public String getString(String columnLabel) {
329: ensureOpen();
330: return getStringImpl(getCurrent(columnLabel));
331: }
332:
333: private String getStringImpl(Value val) {
334: if (val instanceof Literal) {
335: return SesameUtils.getDataPropertyValue((Literal) val).toString();
336: } else {
337: return val.toString();
338: }
339: }
340:
341: @Override
342: public boolean hasNext() throws OntoDriverException {
343: ensureOpen();
344: try {
345: return result.hasNext();
346: } catch (QueryEvaluationException e) {
347: throw new OntoDriverException(e);
348: }
349: }
350:
351: @Override
352: public void next() throws OntoDriverException {
353: super.next();
354: try {
355: this.current = result.next();
356: } catch (QueryEvaluationException e) {
357: throw new OntoDriverException(e);
358: }
359: }
360:
361: private Object getLiteralValue(int columnIndex) throws OntoDriverException {
362: final Value val = getCurrent(columnIndex);
363: if (!(val instanceof Literal)) {
364: throw new OntoDriverException("Expected value " + val + " to be a literal.");
365: }
366: return SesameUtils.getDataPropertyValue((Literal) val);
367: }
368:
369: private Object getLiteralValue(String columnName) throws OntoDriverException {
370: final Value val = getCurrent(columnName);
371: if (!(val instanceof Literal)) {
372: throw new OntoDriverException("Expected value " + val + " to be a literal.");
373: }
374: return SesameUtils.getDataPropertyValue((Literal) val);
375: }
376:
377: private Value getCurrent(int columnIndex) {
378: ensureState();
379: if (columnIndex < 0 || columnIndex >= bindings.size()) {
380: throw new IllegalArgumentException(
381: "The column index is out of bounds of the column count.");
382: }
383: final Value v = current.getValue(bindings.get(columnIndex));
384: if (v == null) {
385: throw new VariableNotBoundException(
386: "Variable at index " + columnIndex + " is not bound in the current result row.");
387: }
388: return v;
389: }
390:
391: private void ensureState() {
392: if (current == null) {
393: throw new IllegalStateException("Must call next before getting the first value.");
394: }
395: }
396:
397: private Value getCurrent(String columnName) {
398: ensureState();
399: if (!bindings.contains(columnName)) {
400: throw new IllegalArgumentException("Unknown column name " + columnName);
401: }
402: final Value v = current.getValue(columnName);
403: if (v == null) {
404: throw new VariableNotBoundException(
405: "Variable \"" + columnName + "\" is not bound in the current result row.");
406: }
407: return v;
408: }
409: }