Skip to contentMethod: getSingleResult()
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.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.Descriptor;
21: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
22: import cz.cvut.kbss.jopa.model.query.Parameter;
23: import cz.cvut.kbss.jopa.model.query.TypedQuery;
24: import cz.cvut.kbss.jopa.query.QueryHolder;
25: import cz.cvut.kbss.jopa.sessions.ConnectionWrapper;
26: import cz.cvut.kbss.jopa.sessions.MetamodelProvider;
27: import cz.cvut.kbss.jopa.sessions.UnitOfWork;
28: import cz.cvut.kbss.jopa.utils.ErrorUtils;
29: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
30: import cz.cvut.kbss.ontodriver.iteration.ResultRow;
31:
32: import java.net.URI;
33: import java.util.ArrayList;
34: import java.util.List;
35: import java.util.Objects;
36: import java.util.Optional;
37: import java.util.stream.Stream;
38:
39: public class TypedQueryImpl<X> extends AbstractQuery implements TypedQuery<X> {
40:
41: private final Class<X> resultType;
42: private final MetamodelProvider metamodelProvider;
43:
44: private UnitOfWork uow;
45:
46: private Descriptor descriptor;
47:
48: public TypedQueryImpl(final QueryHolder query, final Class<X> resultType,
49: final ConnectionWrapper connection, MetamodelProvider metamodelProvider) {
50: super(query, connection);
51: this.resultType = Objects.requireNonNull(resultType, ErrorUtils.getNPXMessageSupplier("resultType"));
52: this.metamodelProvider = Objects
53: .requireNonNull(metamodelProvider, ErrorUtils.getNPXMessageSupplier("metamodelProvider"));
54: }
55:
56: public void setUnitOfWork(UnitOfWork uow) {
57: this.uow = uow;
58: }
59:
60: @Override
61: public List<X> getResultList() {
62: ensureOpen();
63: try {
64: return getResultListImpl();
65: } catch (OntoDriverException e) {
66: markTransactionForRollback();
67: throw queryEvaluationException(e);
68: } catch (RuntimeException e) {
69: markTransactionForRollback();
70: throw e;
71: }
72: }
73:
74: private List<X> getResultListImpl() throws OntoDriverException {
75: final boolean isEntityType = metamodelProvider.isEntityType(resultType);
76: final Descriptor instDescriptor = descriptor != null ? descriptor : new EntityDescriptor();
77: final List<X> res = new ArrayList<>();
78: executeQuery(rs -> {
79: if (isEntityType) {
80: loadEntityInstance(rs, instDescriptor).ifPresent(res::add);
81: } else {
82: loadResultValue(rs).ifPresent(res::add);
83: }
84: });
85: return res;
86: }
87:
88: private Optional<X> loadEntityInstance(ResultRow resultRow, Descriptor instanceDescriptor) {
89: if (uow == null) {
90: throw new IllegalStateException("Cannot load entity instance without Unit of Work.");
91: }
92: try {
93: assert resultRow.isBound(0);
94: final URI uri = URI.create(resultRow.getString(0));
95: return Optional.ofNullable(uow.readObject(resultType, uri, instanceDescriptor));
96: } catch (OntoDriverException e) {
97: throw new OWLPersistenceException("Unable to load query result as entity of type " + resultType, e);
98: }
99: }
100:
101: private Optional<X> loadResultValue(ResultRow resultRow) {
102: try {
103: return Optional.of(resultRow.getObject(0, resultType));
104: } catch (OntoDriverException e) {
105: throw new OWLPersistenceException("Unable to map the query result to class " + resultType, e);
106: }
107: }
108:
109: @Override
110: public X getSingleResult() {
111: ensureOpen();
112: try {
113: final List<X> res = getResultListImpl();
114:• if (res.isEmpty()) {
115: throw new NoResultException("No result found for query " + query);
116: }
117:• if (res.size() > 1) {
118: throw new NoUniqueResultException("Multiple results found for query " + query);
119: }
120: return res.get(0);
121: } catch (OntoDriverException e) {
122: markTransactionForRollback();
123: throw queryEvaluationException(e);
124: } catch (RuntimeException e) {
125:• if (exceptionCausesRollback(e)) {
126: markTransactionForRollback();
127: }
128: throw e;
129: }
130: }
131:
132: @Override
133: public Stream<X> getResultStream() {
134: final boolean isEntityType = metamodelProvider.isEntityType(resultType);
135: final Descriptor instDescriptor = descriptor != null ? descriptor : new EntityDescriptor();
136: try {
137: return executeQueryForStream(row -> {
138: if (isEntityType) {
139: return loadEntityInstance(row, instDescriptor);
140: } else {
141: return loadResultValue(row);
142: }
143: });
144: } catch (OntoDriverException e) {
145: markTransactionForRollback();
146: throw queryEvaluationException(e);
147: } catch (RuntimeException e) {
148: if (exceptionCausesRollback(e)) {
149: markTransactionForRollback();
150: }
151: throw e;
152: }
153: }
154:
155: @Override
156: public TypedQuery<X> setMaxResults(int maxResults) {
157: ensureOpen();
158: checkNumericParameter(maxResults, "max results");
159: query.setMaxResults(maxResults);
160: return this;
161: }
162:
163: @Override
164: public TypedQuery<X> setFirstResult(int startPosition) {
165: ensureOpen();
166: checkNumericParameter(startPosition, "first result offset");
167: query.setFirstResult(startPosition);
168: return this;
169: }
170:
171: @Override
172: public TypedQuery<X> setParameter(int position, Object value) {
173: super.setParameter(position, value);
174: return this;
175: }
176:
177: @Override
178: public TypedQuery<X> setParameter(int position, String value, String language) {
179: super.setParameter(position, value, language);
180: return this;
181: }
182:
183: @Override
184: public TypedQuery<X> setParameter(String name, Object value) {
185: super.setParameter(name, value);
186: return this;
187: }
188:
189: @Override
190: public TypedQuery<X> setParameter(String name, String value, String language) {
191: super.setParameter(name, value, language);
192: return this;
193: }
194:
195: @Override
196: public <T> TypedQuery<X> setParameter(Parameter<T> parameter, T value) {
197: super.setParameter(parameter, value);
198: return this;
199: }
200:
201: @Override
202: public TypedQuery<X> setParameter(Parameter<String> parameter, String value, String language) {
203: super.setParameter(parameter, value, language);
204: return this;
205: }
206:
207: @Override
208: public TypedQuery<X> setUntypedParameter(int position, Object value) {
209: super.setUntypedParameter(position, value);
210: return this;
211: }
212:
213: @Override
214: public TypedQuery<X> setUntypedParameter(String name, Object value) {
215: super.setUntypedParameter(name, value);
216: return this;
217: }
218:
219: @Override
220: public <T> TypedQuery<X> setUntypedParameter(Parameter<T> parameter, T value) {
221: super.setUntypedParameter(parameter, value);
222: return this;
223: }
224:
225: @Override
226: public TypedQuery<X> setDescriptor(Descriptor descriptor) {
227: this.descriptor = descriptor;
228: return this;
229: }
230: }