1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.openrdf.elmo.sesame;
30
31 import java.io.Closeable;
32 import java.io.IOException;
33 import java.lang.reflect.UndeclaredThrowableException;
34 import java.util.ArrayList;
35 import java.util.Calendar;
36 import java.util.Date;
37 import java.util.GregorianCalendar;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.WeakHashMap;
42
43 import javax.persistence.FlushModeType;
44 import javax.persistence.NoResultException;
45 import javax.persistence.NonUniqueResultException;
46 import javax.persistence.Query;
47 import javax.persistence.TemporalType;
48 import javax.xml.datatype.DatatypeConfigurationException;
49 import javax.xml.datatype.DatatypeConstants;
50 import javax.xml.datatype.DatatypeFactory;
51 import javax.xml.datatype.XMLGregorianCalendar;
52 import javax.xml.namespace.QName;
53
54 import org.openrdf.elmo.ElmoQuery;
55 import org.openrdf.elmo.exceptions.ElmoConversionException;
56 import org.openrdf.elmo.exceptions.ElmoIOException;
57 import org.openrdf.elmo.sesame.iterators.ElmoIteration;
58 import org.openrdf.model.Value;
59 import org.openrdf.model.ValueFactory;
60 import org.openrdf.query.QueryEvaluationException;
61 import org.openrdf.query.TupleQuery;
62 import org.openrdf.query.TupleQueryResult;
63 import org.openrdf.repository.RepositoryConnection;
64
65
66
67
68
69
70 public class SesameQuery implements ElmoQuery, Query {
71
72 protected SesameManager manager;
73
74 protected TupleQuery query;
75
76 private WeakHashMap<Closeable, Object> opened;
77
78 private int firstResult;
79
80 private int maxResults;
81
82 public SesameQuery(SesameManager manager, TupleQuery query) {
83 this.manager = manager;
84 this.opened = new WeakHashMap<Closeable, Object>(4);
85 this.query = query;
86 }
87
88 public void close() {
89 try {
90 for (Closeable c : opened.keySet()) {
91 c.close();
92 }
93 } catch (IOException e) {
94 throw new UndeclaredThrowableException(e);
95 }
96 }
97
98 @SuppressWarnings("unchecked")
99 protected Iterator evaluateQuery() throws QueryEvaluationException {
100 Iterator iter;
101 TupleQueryResult result = query.evaluate();
102 int max = maxResults <= 0 ? 0 : maxResults + firstResult;
103 if (result.getBindingNames().size() > 1) {
104 iter = new ElmoTupleQueryResult(manager, result, max);
105 } else {
106 iter = new ElmoSingleQueryResult(manager, result, max);
107 }
108 return iter;
109 }
110
111 public Iterator evaluate() {
112 try {
113 Iterator result = evaluateQuery();
114 if (result instanceof Closeable)
115 opened.put((Closeable) result, Boolean.TRUE);
116 if (firstResult > 0) {
117 for (int i = 0; i < firstResult && result.hasNext(); i++) {
118 result.next();
119 }
120 }
121 return result;
122 } catch (QueryEvaluationException e) {
123 throw new ElmoIOException(e);
124 }
125 }
126
127 public Object getSingleResult() {
128 Iterator iter = evaluate();
129 try {
130 if (!iter.hasNext())
131 throw new NoResultException("No results");
132 Object result = iter.next();
133 if (iter.hasNext())
134 throw new NonUniqueResultException("More than one result");
135 return result;
136 } finally {
137 ElmoIteration.close(iter);
138 }
139 }
140
141 public List getResultList() {
142 List result = new ArrayList();
143 Iterator iter = evaluate();
144 try {
145 for (int count = 0; iter.hasNext(); count++) {
146 result.add(iter.next());
147 }
148 return result;
149 } finally {
150 ElmoIteration.close(iter);
151 }
152 }
153
154 public Iterator iterator() {
155 return evaluate();
156 }
157
158 public SesameQuery setFirstResult(int startPosition) {
159 this.firstResult = startPosition;
160 return this;
161 }
162
163 public SesameQuery setMaxResults(int maxResult) {
164 this.maxResults = maxResult;
165 return this;
166 }
167
168 public ElmoQuery setParameter(String name, String label, Locale locale) {
169 RepositoryConnection conn = manager.getConnection();
170 ValueFactory vf = conn.getRepository().getValueFactory();
171 if (locale == null) {
172 setBinding(name, vf.createLiteral(label));
173 } else {
174 String lang = locale.toString().toLowerCase().replace('_', '-');
175 setBinding(name, vf.createLiteral(label, lang));
176 }
177 return this;
178 }
179
180 public SesameQuery setParameter(String name, Object value) {
181 if (value instanceof Value) {
182 setBinding(name, (Value) value);
183 } else if (value instanceof QName) {
184 setBinding(name, manager.createResource((QName) value));
185 } else {
186 setBinding(name, manager.getValue(value));
187 }
188 return this;
189 }
190
191 @Override
192 public String toString() {
193 if (query == null)
194 return super.toString();
195 return query.toString();
196 }
197
198 protected void setBinding(String name, Value value) {
199 if (query == null)
200 throw new UnsupportedOperationException();
201 query.setBinding(name, value);
202 }
203
204 public int executeUpdate() {
205 throw new UnsupportedOperationException();
206 }
207
208 public SesameQuery setFlushMode(FlushModeType flushMode) {
209 if (FlushModeType.AUTO.equals(flushMode)) {
210 manager.flush();
211 }
212 return this;
213 }
214
215 public SesameQuery setHint(String hintName, Object value) {
216 return this;
217 }
218
219 public SesameQuery setParameter(String name, Date value,
220 TemporalType temporalType) {
221 int y, M, d, h, m, s, i, z;
222 try {
223 z = DatatypeConstants.FIELD_UNDEFINED;
224 DatatypeFactory factory = DatatypeFactory.newInstance();
225 XMLGregorianCalendar xcal;
226 switch (temporalType) {
227 case DATE:
228 y = value.getYear();
229 M = value.getMonth() + 1;
230 d = value.getDate();
231 xcal = factory.newXMLGregorianCalendarDate(y, M, d, z);
232 break;
233 case TIME:
234 h = value.getHours();
235 m = value.getMinutes();
236 s = value.getSeconds();
237 i = (int) (value.getTime() % 1000);
238 xcal = factory.newXMLGregorianCalendarTime(h, m, s, i, z);
239 break;
240 case TIMESTAMP:
241 y = value.getYear();
242 M = value.getMonth() + 1;
243 d = value.getDate();
244 h = value.getHours();
245 m = value.getMinutes();
246 s = value.getSeconds();
247 i = (int) (value.getTime() % 1000);
248 xcal = factory.newXMLGregorianCalendar(y, M, d, h, m, s, i, z);
249 break;
250 default:
251 throw new AssertionError();
252 }
253 return setParameter(name, xcal);
254 } catch (DatatypeConfigurationException e) {
255 throw new ElmoConversionException(e);
256 }
257 }
258
259 public SesameQuery setParameter(String name, Calendar value,
260 TemporalType temporalType) {
261 assert value instanceof GregorianCalendar : value;
262 GregorianCalendar cal = (GregorianCalendar) value;
263 try {
264 DatatypeFactory factory = DatatypeFactory.newInstance();
265 XMLGregorianCalendar xcal = factory.newXMLGregorianCalendar(cal);
266 switch (temporalType) {
267 case DATE:
268 xcal.setHour(DatatypeConstants.FIELD_UNDEFINED);
269 xcal.setMinute(DatatypeConstants.FIELD_UNDEFINED);
270 xcal.setSecond(DatatypeConstants.FIELD_UNDEFINED);
271 xcal.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
272 break;
273 case TIME:
274 xcal.setYear(DatatypeConstants.FIELD_UNDEFINED);
275 xcal.setMonth(DatatypeConstants.FIELD_UNDEFINED);
276 xcal.setDay(DatatypeConstants.FIELD_UNDEFINED);
277 break;
278 case TIMESTAMP:
279 break;
280 }
281 return setParameter(name, xcal);
282 } catch (DatatypeConfigurationException e) {
283 throw new ElmoConversionException(e);
284 }
285 }
286
287 public SesameQuery setParameter(int arg0, Object arg1) {
288 throw new UnsupportedOperationException(
289 "Parameters by index are not supported");
290 }
291
292 public SesameQuery setParameter(int arg0, Date arg1, TemporalType arg2) {
293 throw new UnsupportedOperationException(
294 "Parameters by index are not supported");
295 }
296
297 public SesameQuery setParameter(int arg0, Calendar arg1, TemporalType arg2) {
298 throw new UnsupportedOperationException(
299 "Parameters by index are not supported");
300 }
301
302 }