View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.sesame;
30  
31  import info.aduna.iteration.CloseableIteration;
32  
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.Collections;
36  import java.util.HashSet;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Set;
40  
41  import org.openrdf.elmo.ElmoProperty;
42  import org.openrdf.elmo.exceptions.ElmoPersistException;
43  import org.openrdf.elmo.exceptions.ElmoIOException;
44  import org.openrdf.elmo.sesame.helpers.PropertyChanger;
45  import org.openrdf.elmo.sesame.iterators.ElmoIteration;
46  import org.openrdf.elmo.sesame.roles.SesameEntity;
47  import org.openrdf.model.Resource;
48  import org.openrdf.model.Statement;
49  import org.openrdf.model.URI;
50  import org.openrdf.model.Value;
51  import org.openrdf.repository.RepositoryConnection;
52  import org.openrdf.repository.RepositoryException;
53  import org.openrdf.repository.contextaware.ContextAwareConnection;
54  
55  /**
56   * A set for a given getResource(), predicate.
57   * 
58   * @author James Leigh
59   * 
60   * @param <E>
61   */
62  public class SesameProperty<E> implements ElmoProperty<E>, Set<E> {
63  
64  	private final SesameEntity bean;
65  
66  	protected PropertyChanger property;
67  
68  	private boolean singleCached;
69  
70  	private E single;
71  
72  	public SesameProperty(SesameEntity bean, PropertyChanger property) {
73  		assert bean != null;
74  		assert property != null;
75  		this.bean = bean;
76  		this.property = property;
77  	}
78  
79  	public void refresh() {
80  		singleCached = false;
81  		single = null;
82  	}
83  
84  	public boolean add(E o) {
85  		Value val = getValue(o);
86  		if (contains(val))
87  			return false;
88  		ContextAwareConnection conn = getConnection();
89  		try {
90  			add(conn, getResource(), val);
91  		} catch (RepositoryException e) {
92  			throw new ElmoPersistException(e);
93  		}
94  		return true;
95  	}
96  
97  	public boolean addAll(Collection<? extends E> c) {
98  		RepositoryConnection conn = getConnection();
99  		boolean modified = false;
100 		try {
101 			boolean autoCommit = conn.isAutoCommit();
102 			if (autoCommit)
103 				conn.setAutoCommit(false);
104 			for (E o : c)
105 				if (add(o))
106 					modified = true;
107 			if (autoCommit)
108 				conn.setAutoCommit(true);
109 		} catch (RepositoryException e) {
110 			throw new ElmoPersistException(e);
111 		}
112 		return modified;
113 	}
114 
115 	public void clear() {
116 		ContextAwareConnection conn = getConnection();
117 		try {
118 			boolean autoCommit = conn.isAutoCommit();
119 			conn.setAutoCommit(false);
120 			CloseableIteration<? extends Statement, RepositoryException> stmts;
121 			stmts = getStatements();
122 			try {
123 				while (stmts.hasNext()) {
124 					remove(conn, stmts.next());
125 				}
126 			} finally {
127 				stmts.close();
128 			}
129 			conn.setAutoCommit(autoCommit);
130 		} catch (RepositoryException e) {
131 			throw new ElmoPersistException(e);
132 		}
133 	}
134 
135 	public boolean contains(Object o) {
136 		Value val = getValue(o);
137 		ContextAwareConnection conn = getConnection();
138 		try {
139 			return conn.hasStatement(getResource(), getURI(), val);
140 		} catch (RepositoryException e) {
141 			throw new ElmoPersistException(e);
142 		}
143 	}
144 
145 	public boolean containsAll(Collection<?> c) {
146 		Iterator<?> e = c.iterator();
147 		while (e.hasNext())
148 			if (!contains(e.next()))
149 				return false;
150 		return true;
151 	}
152 
153 	@Override
154 	public boolean equals(Object o) {
155 		if (o == this)
156 			return true;
157 		if (!o.getClass().equals(this.getClass()))
158 			return false;
159 		SesameProperty<?> p = (SesameProperty<?>) o;
160 		if (!getManager().equals(p.getManager()))
161 			return false;
162 		if (!getResource().equals(p.getResource()))
163 			return false;
164 		if (!property.equals(p.property))
165 			return false;
166 		return true;
167 	}
168 
169 	public Set<E> getAll() {
170 		return this;
171 	}
172 
173 	public E getSingle() {
174 		if (singleCached)
175 			return single;
176 		ElmoIteration<Statement, E> iter = getElmoIteration();
177 		try {
178 			if (iter.hasNext()) {
179 				single = iter.next();
180 			} else {
181 				single = null;
182 			}
183 			singleCached = true;
184 			return single;
185 		} finally {
186 			iter.close();
187 		}
188 	}
189 
190 	@Override
191 	public int hashCode() {
192 		int hashCode = bean.hashCode();
193 		hashCode ^= property.hashCode();
194 		return hashCode;
195 	}
196 
197 	public boolean isEmpty() {
198 		ElmoIteration<Statement, E> iter = getElmoIteration();
199 		try {
200 			return !iter.hasNext();
201 		} finally {
202 			iter.close();
203 		}
204 	}
205 
206 	public Iterator<E> iterator() {
207 		ElmoIteration<Statement, E> iter = getElmoIteration();
208 		if (iter.hasNext()) {
209 			bean.opened(iter);
210 		}
211 		return iter;
212 	}
213 
214 	public boolean remove(Object o) {
215 		Value val = getValue(o);
216 		if (!contains(val))
217 			return false;
218 		ContextAwareConnection conn = getConnection();
219 		try {
220 			remove(conn, getResource(), val);
221 		} catch (RepositoryException e) {
222 			throw new ElmoPersistException(e);
223 		}
224 		return true;
225 	}
226 
227 	public boolean removeAll(Collection<?> c) {
228 		RepositoryConnection conn = getConnection();
229 		boolean modified = false;
230 		try {
231 			boolean autoCommit = conn.isAutoCommit();
232 			if (autoCommit)
233 				conn.setAutoCommit(false);
234 			for (Object o : c)
235 				if (remove(o))
236 					modified = true;
237 			if (autoCommit)
238 				conn.setAutoCommit(true);
239 		} catch (RepositoryException e) {
240 			throw new ElmoPersistException(e);
241 		}
242 		return modified;
243 	}
244 
245 	public boolean retainAll(Collection<?> c) {
246 		RepositoryConnection conn = getConnection();
247 		boolean modified = false;
248 		try {
249 			boolean autoCommit = conn.isAutoCommit();
250 			if (autoCommit)
251 				conn.setAutoCommit(false);
252 			Iterator<E> e = iterator();
253 			while (e.hasNext()) {
254 				if (!c.contains(e.next())) {
255 					e.remove();
256 					modified = true;
257 				}
258 			}
259 			if (autoCommit)
260 				conn.setAutoCommit(true);
261 		} catch (RepositoryException e) {
262 			throw new ElmoPersistException(e);
263 		}
264 		return modified;
265 	}
266 
267 	public void setAll(Set<E> set) {
268 		if (this == set)
269 			return;
270 		if (set == null) {
271 			clear();
272 			return;
273 		}
274 		Set<E> c = new HashSet<E>(set);
275 		RepositoryConnection conn = getConnection();
276 		try {
277 			boolean autoCommit = conn.isAutoCommit();
278 			if (autoCommit)
279 				conn.setAutoCommit(false);
280 			Iterator<E> e = iterator();
281 			while (e.hasNext()) {
282 				Object next = e.next();
283 				if (c.contains(next)) {
284 					c.remove(next);
285 				} else {
286 					e.remove();
287 				}
288 			}
289 			if (c.size() > 0)
290 				addAll(c);
291 			if (autoCommit)
292 				conn.setAutoCommit(true);
293 		} catch (RepositoryException e) {
294 			throw new ElmoPersistException(e);
295 		}
296 	}
297 
298 	public void setSingle(E o) {
299 		if (o == null) {
300 			clear();
301 		} else {
302 			setAll(Collections.singleton(o));
303 		}
304 		single = null;
305 		singleCached = false;
306 	}
307 
308 	public int size() {
309 		CloseableIteration<? extends Statement, RepositoryException> iter;
310 		try {
311 			iter = getStatements();
312 			try {
313 				int size;
314 				for (size = 0; iter.hasNext(); size++)
315 					iter.next();
316 				return size;
317 			} finally {
318 				iter.close();
319 			}
320 		} catch (RepositoryException e) {
321 			throw new ElmoIOException(e);
322 		}
323 	}
324 
325 	public Object[] toArray() {
326 		List<E> list = new ArrayList<E>();
327 		ElmoIteration<Statement, E> iter = getElmoIteration();
328 		try {
329 			while (iter.hasNext()) {
330 				list.add(iter.next());
331 			}
332 		} finally {
333 			iter.close();
334 		}
335 		return list.toArray();
336 	}
337 
338 	public <T> T[] toArray(T[] a) {
339 		List<E> list = new ArrayList<E>();
340 		ElmoIteration<Statement, E> iter = getElmoIteration();
341 		try {
342 			while (iter.hasNext()) {
343 				list.add(iter.next());
344 			}
345 		} finally {
346 			iter.close();
347 		}
348 		return list.toArray(a);
349 	}
350 
351 	@Override
352 	public String toString() {
353 		StringBuilder sb = new StringBuilder();
354 		ElmoIteration<Statement, E> iter = getElmoIteration();
355 		try {
356 			if (iter.hasNext()) {
357 				sb.append(iter.next().toString());
358 			}
359 			while (iter.hasNext()) {
360 				sb.append(", ");
361 				sb.append(iter.next());
362 			}
363 		} finally {
364 			iter.close();
365 		}
366 		return sb.toString();
367 	}
368 
369 	final SesameManager getManager() {
370 		return bean.getSesameManager();
371 	}
372 
373 	final ContextAwareConnection getConnection() {
374 		return getManager().getConnection();
375 	}
376 
377 	final Resource getResource() {
378 		return bean.getSesameResource();
379 	}
380 
381 	final URI getURI() {
382 		return property.getPredicate();
383 	}
384 
385 	void add(ContextAwareConnection conn, Resource subj, Value obj)
386 			throws RepositoryException {
387 		property.add(conn, subj, obj);
388 	}
389 
390 	void remove(ContextAwareConnection conn, Resource subj, Value obj)
391 			throws RepositoryException {
392 		property.remove(conn, subj, obj);
393 	}
394 
395 	void remove(ContextAwareConnection conn, Statement stmt)
396 			throws RepositoryException {
397 		assert stmt.getPredicate().equals(getURI());
398 		remove(conn, stmt.getSubject(), stmt.getObject());
399 	}
400 
401 	@SuppressWarnings("unchecked")
402 	E createInstance(Statement stmt) {
403 		Value value = stmt.getObject();
404 		return (E) getManager().getInstance(value);
405 	}
406 
407 	CloseableIteration<? extends Statement, RepositoryException> getStatements()
408 			throws RepositoryException {
409 		ContextAwareConnection conn = getConnection();
410 		return conn.getStatements(getResource(), getURI(), null);
411 	}
412 
413 	Value getValue(Object instance) {
414 		if (instance instanceof Value)
415 			return (Value) instance;
416 		return getManager().getValue(instance);
417 	}
418 
419 	private ElmoIteration<Statement, E> getElmoIteration() {
420 		try {
421 			return new ElmoIteration<Statement, E>(getStatements()) {
422 
423 				@Override
424 				protected E convert(Statement stmt) {
425 					return createInstance(stmt);
426 				}
427 
428 				@Override
429 				protected void remove(Statement stmt) {
430 					try {
431 						ContextAwareConnection conn = getConnection();
432 						SesameProperty.this.remove(conn, stmt);
433 					} catch (RepositoryException e) {
434 						throw new ElmoPersistException(e);
435 					}
436 				}
437 
438 			};
439 		} catch (RepositoryException e) {
440 			throw new ElmoPersistException(e);
441 		}
442 	}
443 
444 }