Skip to contentMethod: getSingleResult()
1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
5: * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
6: * version.
7: * <p>
8: * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
9: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
10: * details. You should have received a copy of the GNU General Public License along with this program. If not, see
11: * <http://www.gnu.org/licenses/>.
12: */
13: package cz.cvut.kbss.jopa.model;
14:
15: import cz.cvut.kbss.jopa.exceptions.NoResultException;
16: import cz.cvut.kbss.jopa.exceptions.NoUniqueResultException;
17: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
18: import cz.cvut.kbss.jopa.model.query.Parameter;
19: import cz.cvut.kbss.jopa.model.query.Query;
20: import cz.cvut.kbss.jopa.query.QueryHolder;
21: import cz.cvut.kbss.jopa.sessions.ConnectionWrapper;
22: import cz.cvut.kbss.jopa.utils.ErrorUtils;
23: import cz.cvut.kbss.ontodriver.ResultSet;
24: import cz.cvut.kbss.ontodriver.Statement;
25: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
26:
27: import java.net.URI;
28: import java.util.*;
29:
30: public class QueryImpl implements Query {
31:
32: private final QueryHolder query;
33: private final Set<URI> contexts;
34: private final ConnectionWrapper connection;
35:
36: private int maxResults;
37: private boolean useBackupOntology;
38:
39: public QueryImpl(final QueryHolder query, final ConnectionWrapper connection) {
40: this.query = Objects.requireNonNull(query, ErrorUtils.constructNPXMessage("query"));
41: this.connection = Objects.requireNonNull(connection,
42: ErrorUtils.constructNPXMessage("connection"));
43: this.contexts = new HashSet<>();
44: this.useBackupOntology = false;
45: this.maxResults = Integer.MAX_VALUE;
46: }
47:
48: @Override
49: public List getResultList() {
50: try {
51: if (maxResults == 0) {
52: return Collections.emptyList();
53: }
54: return getResultListImpl(maxResults);
55: } catch (OntoDriverException e) {
56: throw queryEvaluationException(e);
57: }
58: }
59:
60: private OWLPersistenceException queryEvaluationException(OntoDriverException e) {
61: final String executedQuery = query.assembleQuery();
62: return new OWLPersistenceException("Exception caught when evaluating query " + executedQuery, e);
63: }
64:
65: @Override
66: public Object getSingleResult() {
67: try {
68: // Call it with maxResults = 2 just to see whether there are more
69: final List<?> list = getResultListImpl(2);
70:• if (list.isEmpty()) {
71: throw new NoResultException("No result found for query " + query);
72: }
73:• if (list.size() > 1) {
74: throw new NoUniqueResultException("Multiple results found for query " + query);
75: }
76: return list.get(0);
77: } catch (OntoDriverException e) {
78: throw queryEvaluationException(e);
79: }
80: }
81:
82: @Override
83: public int getMaxResults() {
84: return maxResults;
85: }
86:
87: @Override
88: public Parameter<?> getParameter(int position) {
89: return query.getParameter(position);
90: }
91:
92: @Override
93: public Parameter<?> getParameter(String name) {
94: return query.getParameter(name);
95: }
96:
97: @Override
98: public Set<Parameter<?>> getParameters() {
99: return query.getParameters();
100: }
101:
102: @Override
103: public boolean isBound(Parameter<?> parameter) {
104: return query.getParameterValue(parameter) != null;
105: }
106:
107: @Override
108: public Object getParameterValue(int position) {
109: final Parameter<?> param = query.getParameter(position);
110: return getParameterValue(param);
111: }
112:
113: @Override
114: public Object getParameterValue(String name) {
115: final Parameter<?> param = query.getParameter(name);
116: return getParameterValue(param);
117: }
118:
119: private IllegalStateException unboundParam(Object param) {
120: return new IllegalStateException("Parameter " + param + " is not bound.");
121: }
122:
123: @Override
124: public <T> T getParameterValue(Parameter<T> parameter) {
125: if (!isBound(parameter)) {
126: throw unboundParam(parameter);
127: }
128: return (T) query.getParameterValue(parameter);
129: }
130:
131: @Override
132: public Query setParameter(int position, Object value) {
133: query.setParameter(query.getParameter(position), value);
134: return this;
135: }
136:
137: @Override
138: public Query setParameter(int position, String value, String language) {
139: query.setParameter(query.getParameter(position), value, language);
140: return this;
141: }
142:
143: @Override
144: public Query setParameter(String name, Object value) {
145: query.setParameter(query.getParameter(name), value);
146: return this;
147: }
148:
149: @Override
150: public Query setParameter(String name, String value, String language) {
151: query.setParameter(query.getParameter(name), value, language);
152: return this;
153: }
154:
155: @Override
156: public <T> Query setParameter(Parameter<T> parameter, T value) {
157: query.setParameter(parameter, value);
158: return this;
159: }
160:
161: @Override
162: public Query setParameter(Parameter<String> parameter, String value, String language) {
163: query.setParameter(parameter, value, language);
164: return this;
165: }
166:
167: public Query setMaxResults(int maxResults) {
168: if (maxResults < 0) {
169: throw new IllegalArgumentException(
170: "Cannot set maximum number of results to less than 0.");
171: }
172: this.maxResults = maxResults;
173: return this;
174: }
175:
176: /**
177: * Sets ontology used for processing of this query. </p>
178: *
179: * @param useBackupOntology If true, the backup (central) ontology is used, otherwise the transactional ontology is
180: * used (default)
181: */
182: public void setUseBackupOntology(boolean useBackupOntology) {
183: this.useBackupOntology = useBackupOntology;
184: }
185:
186: private List<?> getResultListImpl(int maxResults) throws OntoDriverException {
187: assert maxResults > 0;
188:
189: final Statement stmt = connection.createStatement();
190: setTargetOntology(stmt);
191: URI[] uris = new URI[contexts.size()];
192: uris = contexts.toArray(uris);
193: try (ResultSet rs = stmt.executeQuery(query.assembleQuery(), uris)) {
194: final int columnCount = rs.getColumnCount();
195: int cnt = 0;
196: final List<Object> res = new ArrayList<>();
197: // TODO register this as observer on the result set so that additional results can be loaded asynchronously
198: while (rs.hasNext() && cnt < maxResults) {
199: rs.next();
200: if (columnCount == 1) {
201: res.add(rs.getObject(0));
202: } else {
203: res.add(extractResultRow(rs, columnCount));
204: }
205: cnt++;
206: }
207: return res;
208: }
209: }
210:
211: private void setTargetOntology(Statement stmt) {
212: if (useBackupOntology) {
213: stmt.useOntology(Statement.StatementOntology.CENTRAL);
214: } else {
215: stmt.useOntology(Statement.StatementOntology.TRANSACTIONAL);
216: }
217: }
218:
219: private Object[] extractResultRow(ResultSet rs, int columnCount) throws OntoDriverException {
220: final Object[] row = new Object[columnCount];
221: for (int i = 0; i < columnCount; i++) {
222: final Object ob = rs.getObject(i);
223: row[i] = ob;
224: }
225: return row;
226: }
227:
228: @Override
229: public Query addContext(URI context) {
230: Objects.requireNonNull(context, ErrorUtils.constructNPXMessage("context"));
231: contexts.add(context);
232: return this;
233: }
234:
235: @Override
236: public Query addContexts(Collection<URI> contexts) {
237: Objects.requireNonNull(contexts, ErrorUtils.constructNPXMessage("contexts"));
238: this.contexts.addAll(contexts);
239: return this;
240: }
241:
242: @Override
243: public Query clearContexts() {
244: contexts.clear();
245: return this;
246: }
247: }