001: package org.ontoware.rdfreactor.runtime;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.HashSet;
006: import java.util.Iterator;
007: import java.util.Map;
008: import java.util.Set;
009:
010: import org.ontoware.aifbcommons.collection.ClosableIterator;
011: import org.ontoware.rdf2go.exception.ModelRuntimeException;
012: import org.ontoware.rdf2go.model.Model;
013: import org.ontoware.rdf2go.model.Statement;
014: import org.ontoware.rdf2go.model.node.Node;
015: import org.ontoware.rdf2go.model.node.Resource;
016: import org.ontoware.rdf2go.model.node.URI;
017: import org.ontoware.rdf2go.model.node.Variable;
018: import org.slf4j.Logger;
019: import org.slf4j.LoggerFactory;
020:
021: public class ReactorMap implements Map<URI, Object> {
022:
023: private static final Logger log = LoggerFactory
024: .getLogger(ReactorMap.class);
025:
026: private Model model;
027:
028: private Resource id;
029:
030: public ReactorMap(Model model, Resource id) {
031: this .model = model;
032: this .id = id;
033: }
034:
035: // ////////////////////
036: // implement java.util.Map
037:
038: /**
039: * warning, this is a costly operation, as it iterates over all content
040: * rewriting rdf2go with Sets would maybe help
041: *
042: * @return number of triples matching (this, ANY, ANY)
043: */
044: public int size() {
045: int count = 0;
046: try {
047: ClosableIterator<? extends Statement> it = this .model
048: .findStatements(this .id, Variable.ANY, Variable.ANY);
049: while (it.hasNext()) {
050: it.next();
051: count++;
052: }
053: } catch (Exception e) {
054: throw new RuntimeException(e);
055: }
056: return count;
057: }
058:
059: /**
060: * @return true if model contains at least one triple (this, ANY, ANY)
061: */
062: public boolean isEmpty() {
063: try {
064: return !this .model.contains(this .id, Variable.ANY,
065: Variable.ANY);
066: } catch (Exception e) {
067: throw new RuntimeException(e);
068: }
069: }
070:
071: /**
072: * @return true if model contains at least one triple (this, key, ANY)
073: */
074: public boolean containsKey(Object key) {
075: if (key instanceof URI)
076: try {
077: return !this .model.contains(this .id, (URI) key,
078: Variable.ANY);
079: } catch (Exception e) {
080: throw new RuntimeException(e);
081: }
082: else {
083: throw new ClassCastException(
084: "an instance of "
085: + key.getClass()
086: + " can never be contained in this map, only URIs can");
087: }
088: }
089:
090: /**
091: * @return true if model contains at least one triple (this, ANY, value)
092: * @throws ModelRuntimeException
093: * if object could not be converted to an RDF object
094: */
095: public boolean containsValue(Object value) {
096: try {
097: Node node = TypeUtils.toNode(value);
098: // if no exception, node not null
099: assert node != null;
100: return this .model.contains(this .id, Variable.ANY, node);
101: } catch (ModelRuntimeException e) {
102: log.debug("an instance of " + value.getClass()
103: + " can never be contained in this map");
104: return false;
105: }
106: }
107:
108: /**
109: * @return the first instance of (this, key, ANY)
110: */
111: public Object get(Object key) {
112: if (key instanceof URI) {
113: try {
114: return FORD.get(this .id, (URI) key, Object.class);
115: } catch (RDFDataException e) {
116: // TODO: is this what users want?
117: throw new RuntimeException(e);
118: }
119: } else
120: throw new ClassCastException(
121: "an instance of "
122: + key.getClass()
123: + " can never be contained in this map, only URIs can");
124: }
125:
126: /**
127: * Add triple (this, key, value) to the model
128: *
129: * @param key
130: * @param value
131: * @return old value x of triple (this, key, x)
132: */
133: public Object put(URI key, Object value) {
134: if (value == null)
135: throw new NullPointerException(
136: "This RDF backed Map cannot store null values");
137:
138: if (key instanceof URI) {
139: Object oldValue = get(key);
140: try {
141: FORD.set(this .id, (URI) key, value);
142: } catch (RuntimeException e) {
143: throw new IllegalArgumentException(
144: "Could not store value of type "
145: + value.getClass());
146: }
147: return oldValue;
148: } else
149: throw new ClassCastException(
150: "an instance of "
151: + key.getClass()
152: + " can never be contained in this map, only URIs can");
153: }
154:
155: /**
156: * Remove all triples in the model matching (this, key, ANY)
157: *
158: * @param key,
159: * is Subject of the triple
160: * @return old value x of (this, key, x)
161: */
162: public Object remove(Object key) {
163: if (key == null)
164: throw new NullPointerException("key may not be null");
165:
166: if (key instanceof URI) {
167: try {
168: Object oldValue = FORD.get(this .id, (URI) key,
169: Object.class);
170: FORD.removeAll(this .id, (URI) key);
171: return oldValue;
172: } catch (RDFDataException e) {
173: // TODO: is this what users want?
174: throw new RuntimeException(e);
175: }
176: } else
177: throw new ClassCastException(
178: "an instance of "
179: + key.getClass()
180: + " can never be contained in this map, only URIs can");
181: }
182:
183: /**
184: * Put all URI/Object pairs in the given Map t into the model
185: *
186: * @param t,
187: * Map with URI/Object pairs
188: */
189: public void putAll(Map<? extends URI, ? extends Object> t) {
190: // TODO use generics better?
191: Iterator<?> it = t.entrySet().iterator();
192: while (it.hasNext()) {
193: Entry<?, ?> entry = (Entry) it.next();
194: URI uri = (URI) entry.getKey();
195: put(uri, entry.getValue());
196: }
197: }
198:
199: /**
200: * remove all triples (this, ANY, ANY) from the model
201: */
202: public void clear() {
203: this .model
204: .removeStatements(this .id, Variable.ANY, Variable.ANY);
205: }
206:
207: /**
208: * @return all Predicates x of triples matching (this, x, ANY)
209: */
210: public Set<URI> keySet() {
211: Set<URI> keyset = new HashSet<URI>();
212: try {
213: ClosableIterator<? extends Statement> it = this .model
214: .findStatements(this .id, Variable.ANY, Variable.ANY);
215: while (it.hasNext()) {
216: keyset.add(it.next().getPredicate());
217: }
218: it.close();
219: return keyset;
220: } catch (Exception e) {
221: throw new RuntimeException(e);
222: }
223: }
224:
225: /**
226: * @return all Objects x of triples matching (this, ANY, x)
227: */
228: public Collection<Object> values() {
229: Collection<Object> values = new ArrayList<Object>();
230: try {
231: ClosableIterator<? extends Statement> it = this .model
232: .findStatements(this .id, Variable.ANY, Variable.ANY);
233: while (it.hasNext()) {
234: values.add(it.next().getObject());
235: }
236: it.close();
237: return values;
238: } catch (Exception e) {
239: throw new RuntimeException(e);
240: }
241: }
242:
243: /**
244: * @return a Set of Entrys, each containing a Predicate x and Object y, for
245: * every triple matching (this, x, y)
246: */
247: public Set<Entry<URI, Object>> entrySet() {
248: Set<Entry<URI, Object>> entries = new HashSet<Entry<URI, Object>>();
249: try {
250:
251: ClosableIterator<? extends Statement> it = this .model
252: .findStatements(this .id, Variable.ANY, Variable.ANY);
253: while (it.hasNext()) {
254: Statement stmt = it.next();
255: Map.Entry<URI, Object> e = new EntryImpl<URI, Object>(
256: this , stmt.getPredicate(), stmt.getObject());
257: entries.add(e);
258: }
259: it.close();
260: return entries;
261: } catch (Exception e) {
262: throw new RuntimeException(e);
263: }
264: }
265:
266: /**
267: * <b>EntryImpl</b> is used by ReactorBaseImpl.entrySet() to keep the
268: * connection between an URI x used as the subject and an Object y used as
269: * the object of a statement (this, x, y) in the model.
270: *
271: * We habe to implement the Map.Entry<?,?> interface because we want to
272: * allow setting the value of the Object y, and we need to know the
273: * underlying ReactorBase instance for that.
274: *
275: * @author mvo
276: *
277: * @param <K>
278: * @param <V>
279: */
280: class EntryImpl<K, V> implements Map.Entry<URI, Object> {
281:
282: private URI predicate;
283:
284: private Object object;
285:
286: private ReactorMap base;
287:
288: public EntryImpl(ReactorMap base, URI predicate, Object object) {
289: this .predicate = predicate;
290: this .object = object;
291: this .base = base;
292: }
293:
294: public URI getKey() {
295: return this .predicate;
296: }
297:
298: public Object getValue() {
299: return this .object;
300: }
301:
302: /**
303: * Set the value x for the triple (this, predicate, x) corresponding to
304: * this EntryImpl instance. We need the underlying ReactorBase instance
305: * for this, because it is connected to the model.
306: *
307: * @param value
308: * is the Object of a triple
309: * @return the old value
310: */
311: public Object setValue(Object value) {
312: Object oldValue = this.base.get(predicate);
313: FORD.set(base.id, predicate, value);
314: return oldValue;
315: }
316:
317: }
318:
319: }
|