Skip to content

Method: getParameter(int)

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.jopa.model;
16:
17: import cz.cvut.kbss.jopa.exceptions.NoResultException;
18: import cz.cvut.kbss.jopa.exceptions.NoUniqueResultException;
19: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
20: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
21: import cz.cvut.kbss.jopa.model.query.Parameter;
22: import cz.cvut.kbss.jopa.model.query.TypedQuery;
23: import cz.cvut.kbss.jopa.query.QueryHolder;
24: import cz.cvut.kbss.jopa.sessions.ConnectionWrapper;
25: import cz.cvut.kbss.jopa.sessions.MetamodelProvider;
26: import cz.cvut.kbss.jopa.sessions.UnitOfWork;
27: import cz.cvut.kbss.jopa.utils.ErrorUtils;
28: import cz.cvut.kbss.ontodriver.ResultSet;
29: import cz.cvut.kbss.ontodriver.Statement;
30: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
31:
32: import java.net.URI;
33: import java.util.*;
34:
35: public class TypedQueryImpl<ResultElement> implements TypedQuery<ResultElement> {
36:
37: private final QueryHolder query;
38: private final Set<URI> contexts;
39: private final Class<ResultElement> resultType;
40: private final ConnectionWrapper connection;
41: private final MetamodelProvider metamodelProvider;
42:
43: private UnitOfWork uow;
44:
45: private boolean useBackupOntology;
46: private int maxResults;
47:
48: public TypedQueryImpl(final QueryHolder query, final Class<ResultElement> resultType,
49: final ConnectionWrapper connection,
50: MetamodelProvider metamodelProvider) {
51: this.query = Objects.requireNonNull(query, ErrorUtils.constructNPXMessage("query"));
52: this.resultType = Objects.requireNonNull(resultType, ErrorUtils.constructNPXMessage("resultType"));
53: this.connection = Objects.requireNonNull(connection,
54: ErrorUtils.constructNPXMessage("connection"));
55: this.metamodelProvider = Objects.requireNonNull(metamodelProvider,
56: ErrorUtils.constructNPXMessage("metamodelProvider"));
57: this.contexts = new HashSet<>();
58: this.maxResults = Integer.MAX_VALUE;
59: }
60:
61: public void setUnitOfWork(UnitOfWork uow) {
62: this.uow = uow;
63: }
64:
65: @Override
66: public List<ResultElement> getResultList() {
67: if (maxResults == 0) {
68: return Collections.emptyList();
69: }
70: List<ResultElement> list;
71: try {
72: list = getResultListImpl(maxResults);
73: } catch (OntoDriverException e) {
74: throw queryEvaluationException(e);
75: }
76:
77: return list;
78: }
79:
80: private OWLPersistenceException queryEvaluationException(OntoDriverException e) {
81: final String executedQuery = query.assembleQuery();
82: return new OWLPersistenceException("Exception caught when evaluating query " + executedQuery, e);
83: }
84:
85: @Override
86: public ResultElement getSingleResult() {
87: try {
88: // call it with maxResults = 2 just to see whether there are
89: // multiple results
90: final List<ResultElement> res = getResultListImpl(2);
91: if (res.isEmpty()) {
92: throw new NoResultException("No result found for query " + query);
93: }
94: if (res.size() > 1) {
95: throw new NoUniqueResultException("Multiple results found for query " + query);
96: }
97: return res.get(0);
98: } catch (OntoDriverException e) {
99: throw queryEvaluationException(e);
100: }
101: }
102:
103: @Override
104: public TypedQuery<ResultElement> setMaxResults(int maxResults) {
105: if (maxResults < 0) {
106: throw new IllegalArgumentException(
107: "Cannot set maximum number of results to less than 0.");
108: }
109: this.maxResults = maxResults;
110: return this;
111: }
112:
113: @Override
114: public int getMaxResults() {
115: return maxResults;
116: }
117:
118: @Override
119: public Parameter<?> getParameter(int position) {
120: return query.getParameter(position);
121: }
122:
123: @Override
124: public Parameter<?> getParameter(String name) {
125: return query.getParameter(name);
126: }
127:
128: @Override
129: public Set<Parameter<?>> getParameters() {
130: return query.getParameters();
131: }
132:
133: @Override
134: public boolean isBound(Parameter<?> parameter) {
135: return query.getParameterValue(parameter) != null;
136: }
137:
138: @Override
139: public Object getParameterValue(int position) {
140: final Parameter<?> param = query.getParameter(position);
141: return getParameterValue(param);
142: }
143:
144: @Override
145: public Object getParameterValue(String name) {
146: final Parameter<?> param = query.getParameter(name);
147: return getParameterValue(param);
148: }
149:
150: private IllegalStateException unboundParam(Object param) {
151: return new IllegalStateException("Parameter " + param + " is not bound.");
152: }
153:
154: @Override
155: public <T> T getParameterValue(Parameter<T> parameter) {
156: if (!isBound(parameter)) {
157: throw unboundParam(parameter);
158: }
159: return (T) query.getParameterValue(parameter);
160: }
161:
162: @Override
163: public TypedQuery<ResultElement> setParameter(int position, Object value) {
164: query.setParameter(query.getParameter(position), value);
165: return this;
166: }
167:
168: @Override
169: public TypedQuery<ResultElement> setParameter(int position, String value, String language) {
170: query.setParameter(query.getParameter(position), value, language);
171: return this;
172: }
173:
174: @Override
175: public TypedQuery<ResultElement> setParameter(String name, Object value) {
176: query.setParameter(query.getParameter(name), value);
177: return this;
178: }
179:
180: @Override
181: public TypedQuery<ResultElement> setParameter(String name, String value, String language) {
182: query.setParameter(query.getParameter(name), value, language);
183: return this;
184: }
185:
186: @Override
187: public <T> TypedQuery<ResultElement> setParameter(Parameter<T> parameter, T value) {
188: query.setParameter(parameter, value);
189: return this;
190: }
191:
192: @Override
193: public TypedQuery<ResultElement> setParameter(Parameter<String> parameter, String value, String language) {
194: query.setParameter(parameter, value, language);
195: return this;
196: }
197:
198: private List<ResultElement> getResultListImpl(int maxResults) throws OntoDriverException {
199: assert maxResults > 0;
200: final Statement stmt = connection.createStatement();
201: if (useBackupOntology) {
202: stmt.useOntology(Statement.StatementOntology.CENTRAL);
203: } else {
204: stmt.useOntology(Statement.StatementOntology.TRANSACTIONAL);
205: }
206: URI[] arr = new URI[contexts.size()];
207: arr = contexts.toArray(arr);
208: try (ResultSet rs = stmt.executeQuery(query.assembleQuery(), arr)) {
209: final List<ResultElement> res = new ArrayList<>();
210: // TODO register this as observer on the result set so that additional results can be loaded asynchronously
211: int cnt = 0;
212: final URI ctx = arr.length > 0 ? arr[0] : null;
213: final boolean isTypeManaged = metamodelProvider.isTypeManaged(resultType);
214: while (rs.hasNext() && cnt < maxResults) {
215: rs.next();
216: if (isTypeManaged) {
217: res.add(loadEntityInstance(rs, ctx));
218: } else {
219: res.add(loadResultValue(rs));
220: }
221: cnt++;
222: }
223: return res;
224: }
225: }
226:
227: private ResultElement loadEntityInstance(ResultSet resultSet, URI context) throws OntoDriverException {
228: if (uow == null) {
229: throw new IllegalStateException("Cannot load entity instance without Unit of Work.");
230: }
231: final URI uri = URI.create(resultSet.getString(0));
232: // TODO Setting the context like this won't work for queries over multiple contexts
233: final EntityDescriptor descriptor = new EntityDescriptor(context);
234:
235: final ResultElement entity = uow.readObject(resultType, uri, descriptor);
236: if (entity == null) {
237: throw new OWLPersistenceException(
238: "Fatal error, unable to load entity for primary key already found by query "
239: + query);
240: }
241: return entity;
242: }
243:
244: private ResultElement loadResultValue(ResultSet resultSet) throws OntoDriverException {
245: try {
246: return resultSet.getObject(0, resultType);
247: } catch (OntoDriverException e) {
248: throw new OWLPersistenceException("Unable to map the query result to class " + resultType, e);
249: }
250: }
251:
252: @Override
253: public TypedQuery<ResultElement> addContext(URI context) {
254: Objects.requireNonNull(context, ErrorUtils.constructNPXMessage("context"));
255: contexts.add(context);
256: return this;
257: }
258:
259: @Override
260: public TypedQuery<ResultElement> addContexts(Collection<URI> contexts) {
261: Objects.requireNonNull(contexts, ErrorUtils.constructNPXMessage("contexts"));
262: this.contexts.addAll(contexts);
263: return this;
264: }
265:
266: @Override
267: public TypedQuery<ResultElement> clearContexts() {
268: contexts.clear();
269: return this;
270: }
271:
272: /**
273: * Sets ontology used for processing of this query. </p>
274: *
275: * @param useBackupOntology If true, the backup (central) ontology is used, otherwise the transactional ontology is
276: * used (default)
277: */
278: public void setUseBackupOntology(boolean useBackupOntology) {
279: this.useBackupOntology = useBackupOntology;
280: }
281: }