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.behaviours;
30
31 import info.aduna.iteration.CloseableIteration;
32
33 import java.util.AbstractSequentialList;
34 import java.util.ArrayList;
35 import java.util.ListIterator;
36 import java.util.NoSuchElementException;
37
38 import org.openrdf.elmo.Entity;
39 import org.openrdf.elmo.Mergeable;
40 import org.openrdf.elmo.Refreshable;
41 import org.openrdf.elmo.annotations.intercepts;
42 import org.openrdf.elmo.annotations.rdf;
43 import org.openrdf.elmo.exceptions.ElmoIOException;
44 import org.openrdf.elmo.exceptions.ElmoPersistException;
45 import org.openrdf.elmo.sesame.SesameManager;
46 import org.openrdf.elmo.sesame.iterators.ElmoIteration;
47 import org.openrdf.elmo.sesame.roles.SesameEntity;
48 import org.openrdf.model.BNode;
49 import org.openrdf.model.Resource;
50 import org.openrdf.model.Statement;
51 import org.openrdf.model.URI;
52 import org.openrdf.model.Value;
53 import org.openrdf.model.ValueFactory;
54 import org.openrdf.model.vocabulary.RDF;
55 import org.openrdf.repository.RepositoryConnection;
56 import org.openrdf.repository.RepositoryException;
57 import org.openrdf.repository.contextaware.ContextAwareConnection;
58
59
60
61
62
63
64
65
66 @rdf("http://www.w3.org/1999/02/22-rdf-syntax-ns#List")
67 public class SesameList extends AbstractSequentialList<Object> implements
68 java.util.List<Object>, Refreshable, Mergeable {
69
70 SesameManager manager;
71
72 Resource resource;
73
74 private int _size = -1;
75
76 private SesameList parent;
77
78 public SesameList(Entity bean) {
79 SesameEntity sbean = (SesameEntity) bean;
80 this.manager = sbean.getSesameManager();
81 this.resource = sbean.getSesameResource();
82 }
83
84 public void refresh() {
85 _size = -1;
86 if (parent != null)
87 parent.refresh();
88 }
89
90 public void merge(Object source) {
91 if (source instanceof java.util.List) {
92 clear();
93 addAll((java.util.List) source);
94 }
95 }
96
97 ValueFactory getValueFactory() {
98 RepositoryConnection conn = manager.getConnection();
99 return conn.getRepository().getValueFactory();
100 }
101
102 private ElmoIteration<Statement, Value> getStatements(Resource subj,
103 URI pred, Value obj) {
104 try {
105 CloseableIteration<? extends Statement, RepositoryException> stmts;
106 ContextAwareConnection conn = manager.getConnection();
107 stmts = conn.getStatements(subj, pred, obj);
108 return new ElmoIteration<Statement, Value>(stmts) {
109 @Override
110 protected Value convert(Statement stmt) throws Exception {
111 return stmt.getObject();
112 }
113 };
114 } catch (RepositoryException e) {
115 throw new ElmoIOException(e);
116 }
117 }
118
119 void addStatement(Resource subj, URI pred, Value obj) {
120 if (obj == null)
121 return;
122 try {
123 ContextAwareConnection conn = manager.getConnection();
124 conn.add(subj, pred, obj);
125 } catch (RepositoryException e) {
126 throw new ElmoPersistException(e);
127 }
128 }
129
130 void removeStatements(Resource subj, URI pred, Value obj) {
131 try {
132 ContextAwareConnection conn = manager.getConnection();
133 conn.remove(subj, pred, obj);
134 } catch (RepositoryException e) {
135 throw new ElmoPersistException(e);
136 }
137 }
138
139 @Override
140 public int size() {
141 if (_size < 0) {
142 synchronized (this) {
143 if (_size < 0) {
144 Resource list = resource;
145 int size;
146 for (size = 0; list != null && !list.equals(RDF.NIL); size++) {
147 Resource nlist = getRest(list);
148 if (nlist == null && getFirst(list) == null)
149 break;
150 list = nlist;
151 }
152 _size = size;
153 }
154 }
155 }
156 return _size;
157 }
158
159 @Override
160 public ListIterator<Object> listIterator(final int index) {
161 return new ListIterator<Object>() {
162 private ArrayList<Resource> prevLists = new ArrayList<Resource>();
163
164 private boolean removed;
165
166 Resource list;
167 {
168 for (int i = 0; i < index; i++) {
169 next();
170 }
171 }
172
173 public void add(Object o) {
174 RepositoryConnection conn = manager.getConnection();
175 try {
176 boolean autoCommit = conn.isAutoCommit();
177 if (autoCommit)
178 conn.setAutoCommit(false);
179 if (resource.equals(RDF.NIL)) {
180
181 throw new ElmoPersistException(
182 "cannot add a value to the nil list");
183
184
185
186
187
188
189 }
190 Value value = o == null ? null : manager.getValue(o);
191 if (getFirst(resource) == null) {
192
193 list = resource;
194 addStatement(list, RDF.FIRST, value);
195 addStatement(list, RDF.REST, RDF.NIL);
196 } else if (list == null) {
197
198 Value first = getFirst(resource);
199 Resource rest = getRest(resource);
200 BNode newList = getValueFactory().createBNode();
201 addStatement(newList, RDF.FIRST, first);
202 addStatement(newList, RDF.REST, rest);
203 removeStatements(resource, RDF.FIRST, first);
204 removeStatements(resource, RDF.REST, rest);
205 addStatement(resource, RDF.FIRST, value);
206 addStatement(resource, RDF.REST, newList);
207 } else if (!list.equals(RDF.NIL)) {
208 Resource rest = getRest(list);
209 BNode newList = getValueFactory().createBNode();
210 removeStatements(list, RDF.REST, rest);
211 addStatement(list, RDF.REST, newList);
212 addStatement(newList, RDF.FIRST, value);
213 addStatement(newList, RDF.REST, rest);
214 } else {
215
216 throw new NoSuchElementException();
217 }
218 if (autoCommit)
219 conn.setAutoCommit(true);
220 refresh();
221 } catch (RepositoryException e) {
222 throw new ElmoPersistException(e);
223 }
224 }
225
226 public void set(Object o) {
227 RepositoryConnection conn = manager.getConnection();
228 try {
229 boolean autoCommit = conn.isAutoCommit();
230 if (autoCommit)
231 conn.setAutoCommit(false);
232 if (resource.equals(RDF.NIL)) {
233
234 throw new NoSuchElementException();
235 } else if (list.equals(RDF.NIL)) {
236
237 throw new NoSuchElementException();
238 } else {
239 Value first = getFirst(list);
240 removeStatements(list, RDF.FIRST, first);
241 if (o != null) {
242 Value obj = manager.getValue(o);
243 addStatement(list, RDF.FIRST, obj);
244 }
245 }
246 if (autoCommit)
247 conn.setAutoCommit(true);
248 refresh();
249 } catch (RepositoryException e) {
250 throw new ElmoPersistException(e);
251 }
252 }
253
254 public void remove() {
255 RepositoryConnection conn = manager.getConnection();
256 try {
257 boolean autoCommit = conn.isAutoCommit();
258 if (autoCommit)
259 conn.setAutoCommit(false);
260 if (prevLists.size() < 1) {
261
262 Value first = getFirst(list);
263 removeStatements(list, RDF.FIRST, first);
264 Resource next = getRest(list);
265 first = getFirst(next);
266 Resource rest = getRest(next);
267 removeStatements(list, RDF.REST, next);
268 if (first != null) {
269 removeStatements(next, RDF.FIRST, first);
270 addStatement(list, RDF.FIRST, first);
271 }
272 if (rest != null) {
273 removeStatements(next, RDF.REST, rest);
274 addStatement(list, RDF.REST, rest);
275 }
276 } else {
277
278 Resource removedList = list;
279 list = prevLists.remove(prevLists.size() - 1);
280 Value first = getFirst(removedList);
281 Resource rest = getRest(removedList);
282 removeStatements(removedList, RDF.FIRST, first);
283 removeStatements(removedList, RDF.REST, rest);
284 removeStatements(list, RDF.REST, removedList);
285 addStatement(list, RDF.REST, rest);
286 }
287 if (autoCommit)
288 conn.setAutoCommit(true);
289 removed = true;
290 refresh();
291 } catch (RepositoryException e) {
292 throw new ElmoPersistException(e);
293 }
294 }
295
296 public boolean hasNext() {
297 Resource next;
298 if (list == null) {
299 next = resource;
300 } else {
301 next = getRest(list);
302 }
303 return getFirst(next) != null;
304 }
305
306 public Object next() {
307 if (list == null) {
308 list = resource;
309 } else if (!removed) {
310 prevLists.add(list);
311 list = getRest(list);
312 } else {
313 removed = false;
314 }
315 Value first = getFirst(list);
316 if (first == null)
317 throw new NoSuchElementException();
318 return createInstance(first);
319 }
320
321 public int nextIndex() {
322 if (list == null)
323 return 0;
324 return prevLists.size() + 1;
325 }
326
327 public int previousIndex() {
328 return prevLists.size() - 1;
329 }
330
331 public boolean hasPrevious() {
332 return prevLists.size() > 0;
333 }
334
335 public Object previous() {
336 list = prevLists.remove(prevLists.size() - 1);
337 removed = false;
338 Value first = getFirst(list);
339 if (first == null)
340 throw new NoSuchElementException();
341 return createInstance(first);
342 }
343
344 private Object createInstance(Value first) {
345 return manager.getInstance(first);
346 }
347 };
348 }
349
350 @Override
351 @intercepts(method="toString",argc=0)
352 public String toString() {
353 return super.toString();
354 }
355
356 Value getFirst(Resource list) {
357 if (list == null)
358 return null;
359 ElmoIteration<Statement, Value> stmts;
360 stmts = getStatements(list, RDF.FIRST, null);
361 try {
362 if (stmts.hasNext())
363 return stmts.next();
364 return null;
365 } finally {
366 stmts.close();
367 }
368 }
369
370 Resource getRest(Resource list) {
371 if (list == null)
372 return null;
373 ElmoIteration<Statement, Value> stmts;
374 stmts = getStatements(list, RDF.REST, null);
375 try {
376 if (stmts.hasNext())
377 return (Resource) stmts.next();
378 return null;
379 } finally {
380 stmts.close();
381 }
382 }
383 }