001: /*
002: * LICENSE INFORMATION
003: * Copyright 2005-2007 by FZI (http://www.fzi.de).
004: * Licensed under a BSD license (http://www.opensource.org/licenses/bsd-license.php)
005: * <OWNER> = Max Völkel
006: * <ORGANIZATION> = FZI Forschungszentrum Informatik Karlsruhe, Karlsruhe, Germany
007: * <YEAR> = 2007
008: *
009: * Project information at http://semweb4j.org/rdf2go
010: */
011: package org.ontoware.rdf2go.model.impl;
012:
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.io.OutputStream;
016: import java.io.Reader;
017: import java.io.StringWriter;
018: import java.io.Writer;
019: import java.util.Collection;
020: import java.util.Iterator;
021: import java.util.LinkedList;
022: import java.util.List;
023:
024: import org.ontoware.aifbcommons.collection.ClosableIterator;
025: import org.ontoware.rdf2go.exception.LockException;
026: import org.ontoware.rdf2go.exception.MalformedQueryException;
027: import org.ontoware.rdf2go.exception.ModelRuntimeException;
028: import org.ontoware.rdf2go.exception.SyntaxNotSupportedException;
029: import org.ontoware.rdf2go.model.Diff;
030: import org.ontoware.rdf2go.model.DiffReader;
031: import org.ontoware.rdf2go.model.Model;
032: import org.ontoware.rdf2go.model.ModelSet;
033: import org.ontoware.rdf2go.model.QuadPattern;
034: import org.ontoware.rdf2go.model.QueryResultTable;
035: import org.ontoware.rdf2go.model.QueryRow;
036: import org.ontoware.rdf2go.model.Statement;
037: import org.ontoware.rdf2go.model.Syntax;
038: import org.ontoware.rdf2go.model.node.BlankNode;
039: import org.ontoware.rdf2go.model.node.DatatypeLiteral;
040: import org.ontoware.rdf2go.model.node.LanguageTagLiteral;
041: import org.ontoware.rdf2go.model.node.Node;
042: import org.ontoware.rdf2go.model.node.NodeOrVariable;
043: import org.ontoware.rdf2go.model.node.PlainLiteral;
044: import org.ontoware.rdf2go.model.node.Resource;
045: import org.ontoware.rdf2go.model.node.ResourceOrVariable;
046: import org.ontoware.rdf2go.model.node.URI;
047: import org.ontoware.rdf2go.model.node.UriOrVariable;
048: import org.ontoware.rdf2go.model.node.Variable;
049: import org.ontoware.rdf2go.vocabulary.RDF;
050:
051: public abstract class AbstractModelSetImpl implements ModelSet {
052:
053: public void dump() {
054: Iterator<? extends Model> it = getModels();
055: while (it.hasNext()) {
056: Model m = it.next();
057: System.out.println("Dumping model with context: "
058: + m.getContextURI() + " ----------");
059: m.dump();
060: m.close();
061: }
062: }
063:
064: /* subclasses should overwrite this method for better performance */
065: public void removeAll() throws ModelRuntimeException {
066: List<Model> models = new LinkedList<Model>();
067: Iterator<? extends Model> it = getModels();
068: while (it.hasNext()) {
069: models.add(it.next());
070: }
071: for (Model m : models) {
072: assert m.isOpen();
073: m.removeAll();
074: }
075: }
076:
077: public Statement createStatement(URI context, Resource subject,
078: URI predicate, Node object) {
079: return new StatementImpl(context, subject, predicate, object);
080: }
081:
082: class ModelIterator implements Iterator<Model> {
083:
084: private Iterator<URI> iterator;
085:
086: public ModelIterator(Iterator<URI> modelURIs) {
087: this .iterator = modelURIs;
088: }
089:
090: public boolean hasNext() {
091: return this .iterator.hasNext();
092: }
093:
094: public Model next() {
095: return getModel(this .iterator.next());
096: }
097:
098: public void remove() {
099: this .iterator.next();
100: }
101:
102: }
103:
104: /* subclasses should overwrite this method to read any syntax besides TriX */
105: public void readFrom(Reader in, Syntax syntax) throws IOException,
106: ModelRuntimeException, SyntaxNotSupportedException {
107: if (syntax == Syntax.Trix) {
108: readFrom(in);
109: } else {
110: throw new SyntaxNotSupportedException(
111: "Syntax '"
112: + syntax
113: + "' not supported. Or the adapter implementor was too lazy to override thid method");
114: }
115: }
116:
117: /* subclasses should overwrite this method to read any syntax besides TriX */
118: public void readFrom(InputStream in, Syntax syntax)
119: throws IOException, ModelRuntimeException,
120: SyntaxNotSupportedException {
121: if (syntax == Syntax.Trix) {
122: readFrom(in);
123: } else {
124: throw new SyntaxNotSupportedException(
125: "Syntax '"
126: + syntax
127: + "' not supported. Or the adapter implementor was too lazy to override thid method");
128: }
129: }
130:
131: /* subclasses should overwrite this method to write any syntax besides TriX */
132: public void writeTo(Writer writer, Syntax syntax)
133: throws IOException, ModelRuntimeException,
134: SyntaxNotSupportedException {
135: if (syntax == Syntax.Trix) {
136: writeTo(writer);
137: } else {
138: throw new SyntaxNotSupportedException(
139: "Syntax '"
140: + syntax
141: + "' not supported. Or the adapter implementor was too lazy to override thid method");
142: }
143: }
144:
145: /* subclasses should overwrite this method to write any syntax besides TriX */
146: public void writeTo(OutputStream out, Syntax syntax)
147: throws IOException, ModelRuntimeException,
148: SyntaxNotSupportedException {
149: if (syntax == Syntax.Trix) {
150: writeTo(out);
151: } else {
152: throw new SyntaxNotSupportedException(
153: "Syntax '"
154: + syntax
155: + "' not supported. Or the adapter implementor was too lazy to override thid method");
156: }
157: }
158:
159: public String serialize(Syntax syntax)
160: throws SyntaxNotSupportedException {
161: StringWriter sw = new StringWriter();
162: try {
163: this .writeTo(sw, syntax);
164: } catch (IOException e) {
165: throw new ModelRuntimeException(e);
166: }
167: return sw.getBuffer().toString();
168: }
169:
170: public boolean containsStatements(UriOrVariable contextURI,
171: ResourceOrVariable subject, UriOrVariable predicate,
172: NodeOrVariable object) throws ModelRuntimeException {
173:
174: ClosableIterator<? extends Statement> it = findStatements(
175: contextURI, subject, predicate, object);
176: boolean result = it.hasNext();
177: it.close();
178: return result;
179: }
180:
181: /* subclasses should overwrite this method for better performance */
182: public void addStatement(URI context, Resource subject,
183: URI predicate, Node object) throws ModelRuntimeException {
184: addStatement(createStatement(context, subject, predicate,
185: object));
186: }
187:
188: public void addAll(Iterator<? extends Statement> statement)
189: throws ModelRuntimeException {
190: while (statement.hasNext()) {
191: addStatement(statement.next());
192: }
193: }
194:
195: /* subclasses should overwrite this method for better performance */
196: public void removeStatement(URI context, Resource subject,
197: URI predicate, Node object) throws ModelRuntimeException {
198: removeStatement(createStatement(context, subject, predicate,
199: object));
200: }
201:
202: public void removeAll(Iterator<? extends Statement> statement)
203: throws ModelRuntimeException {
204: while (statement.hasNext()) {
205: removeStatement(statement.next());
206: }
207: }
208:
209: public void removeStatements(QuadPattern quadPattern)
210: throws ModelRuntimeException {
211: removeStatements(quadPattern.getContext(), quadPattern
212: .getSubject(), quadPattern.getPredicate(), quadPattern
213: .getObject());
214: }
215:
216: /* subclasses should overwrite this method for better performance */
217: public void removeStatements(UriOrVariable context,
218: ResourceOrVariable subject, UriOrVariable predicate,
219: NodeOrVariable object) throws ModelRuntimeException {
220:
221: ClosableIterator<? extends Statement> it = findStatements(
222: context, subject, predicate, object);
223: List<Statement> stmts = new LinkedList<Statement>();
224: while (it.hasNext()) {
225: Statement stmt = it.next();
226: stmts.add(stmt);
227: }
228: it.close();
229: for (Statement stmt : stmts) {
230: this .removeStatement(stmt);
231: }
232: }
233:
234: // implement value factory by delgating to default model
235:
236: /* subclasses should overwrite this method for better performance */
237: public BlankNode createBlankNode() {
238: return this .getDefaultModel().createBlankNode();
239: }
240:
241: /* subclasses should overwrite this method for better performance */
242: public BlankNode createBlankNode(String internalID) {
243: return this .getDefaultModel().createBlankNode(internalID);
244: }
245:
246: /* subclasses should overwrite this method for better performance */
247: public URI createURI(String uriString) throws ModelRuntimeException {
248: return this .getDefaultModel().createURI(uriString);
249: }
250:
251: /* subclasses should overwrite this method for better performance */
252: public boolean isValidURI(String uriString) {
253: return this .getDefaultModel().isValidURI(uriString);
254: }
255:
256: /* subclasses should overwrite this method for better performance */
257: public PlainLiteral createPlainLiteral(String literal) {
258: return this .getDefaultModel().createPlainLiteral(literal);
259: }
260:
261: /* subclasses should overwrite this method for better performance */
262: public LanguageTagLiteral createLanguageTagLiteral(String literal,
263: String langugeTag) throws ModelRuntimeException {
264: return this .getDefaultModel().createLanguageTagLiteral(literal,
265: langugeTag);
266: }
267:
268: /* subclasses should overwrite this method for better performance */
269: public DatatypeLiteral createDatatypeLiteral(String literal,
270: URI datatypeURI) throws ModelRuntimeException {
271: return this .getDefaultModel().createDatatypeLiteral(literal,
272: datatypeURI);
273: }
274:
275: /* subclasses should overwrite this method for better performance */
276: public Statement createStatement(Resource subject, URI predicate,
277: Node object) {
278: return this .getDefaultModel().createStatement(subject,
279: predicate, object);
280: }
281:
282: /* subclasses should overwrite this method for better performance */
283: public URI newRandomUniqueURI() {
284: return this .getDefaultModel().newRandomUniqueURI();
285: }
286:
287: // naive locking
288:
289: private boolean locked = false;
290:
291: /* subclasses should overwrite this method for better performance */
292: public boolean isLocked() {
293: return this .locked;
294: }
295:
296: /* subclasses should overwrite this method for better performance */
297: public void lock() throws LockException {
298: if (isLocked())
299: throw new LockException("Already locked");
300: this .locked = true;
301: }
302:
303: /* subclasses should overwrite this method for better performance */
304: public void unlock() {
305: this .locked = false;
306: }
307:
308: // findable modelset
309:
310: public boolean contains(Statement s) throws ModelRuntimeException {
311: QuadPattern quadPattern = new QuadPatternImpl(s.getContext(), s
312: .getSubject(), s.getPredicate(), s.getObject());
313: ClosableIterator<? extends Statement> x = findStatements(quadPattern);
314: boolean result = x.hasNext();
315: x.close();
316: return result;
317: }
318:
319: /* subclasses should overwrite this method for better performance */
320: public long countStatements(QuadPattern pattern)
321: throws ModelRuntimeException {
322: if (pattern.getContext() == Variable.ANY) {
323: // match all
324: long count = 0;
325: Iterator<?> it = getModels();
326: while (it.hasNext()) {
327: Model m = (Model) it.next();
328: count += m.countStatements(pattern);
329: }
330: return count;
331: }
332: // else
333: assert pattern.getContext() instanceof URI;
334: Model m = getModel((URI) pattern.getContext());
335: return m.countStatements(pattern);
336: }
337:
338: /**
339: * Inefficient: Looks into each model and asks to match the triplepattern
340: * part of the quad pattern.
341: */
342: /* subclasses should overwrite this method for better performance */
343: public ClosableIterator<Statement> findStatements(
344: QuadPattern pattern) throws ModelRuntimeException {
345: if (pattern.getContext() == Variable.ANY)
346: // match all
347: return new LazyUnionModelIterator(this , pattern);
348: // else
349: assert pattern.getContext() instanceof URI;
350: Model m = getModel((URI) pattern.getContext());
351: return m.findStatements(pattern);
352: }
353:
354: public ClosableIterator<Statement> findStatements(
355: UriOrVariable contextURI, ResourceOrVariable subject,
356: UriOrVariable predicate, NodeOrVariable object)
357: throws ModelRuntimeException {
358: QuadPattern quadPattern = this .createQuadPattern(contextURI,
359: subject, predicate, object);
360: return findStatements(quadPattern);
361: }
362:
363: /* subclasses should overwrite this method for better performance */
364: public ClosableIterator<Statement> iterator() {
365: return new LazyUnionModelIterator(this , new QuadPatternImpl(
366: Variable.ANY, Variable.ANY, Variable.ANY, Variable.ANY));
367: }
368:
369: /* subclasses should overwrite this method for better performance */
370: public boolean addModel(Model model) {
371: for (Statement s : model) {
372: addStatement(model.getContextURI(), s.getSubject(), s
373: .getPredicate(), s.getObject());
374: }
375: return true;
376: }
377:
378: /**
379: * @throws ModelRuntimeException
380: * if the ModelSet is locked
381: */
382: public void update(DiffReader diff) throws ModelRuntimeException {
383: synchronized (this ) {
384: if (this .isLocked()) {
385: throw new ModelRuntimeException(
386: "ModelSet is locked, cannot perform an update.");
387: }
388: // remove
389: Iterator<? extends Statement> it = diff.getRemoved()
390: .iterator();
391: while (it.hasNext()) {
392: Statement stmt = it.next();
393: this .removeStatement(stmt);
394: }
395: // add
396: it = diff.getAdded().iterator();
397: while (it.hasNext()) {
398: Statement stmt = it.next();
399: this .addStatement(stmt);
400: }
401: }
402: }
403:
404: /** sublcasses should override this method for performance */
405: public boolean isEmpty() {
406: return size() == 0;
407: }
408:
409: // work around Sesame not having this yet
410: /* subclasses should overwrite this method for better performance */
411: public boolean sparqlAsk(String query)
412: throws ModelRuntimeException, MalformedQueryException {
413: QueryResultTable table = sparqlSelect(query);
414: ClosableIterator<QueryRow> it = table.iterator();
415: boolean result = it.hasNext();
416: it.close();
417: return result;
418: }
419:
420: /* fast, no need to override */
421: public BlankNode createReficationOf(Statement statement) {
422: BlankNode bnode = createBlankNode();
423: return (BlankNode) createReficationOf(statement, bnode);
424: }
425:
426: /* reifications live in the context where the statement is */
427: public Resource createReficationOf(Statement statement,
428: Resource resource) {
429: Diff diff = new DiffImpl();
430: diff.addStatement(createStatement(statement.getContext(),
431: resource, RDF.type, RDF.Statement));
432: diff.addStatement(createStatement(statement.getContext(),
433: resource, RDF.subject, statement.getSubject()));
434: diff.addStatement(createStatement(statement.getContext(),
435: resource, RDF.predicate, statement.getPredicate()));
436: diff.addStatement(createStatement(statement.getContext(),
437: resource, RDF.object, statement.getObject()));
438: update(diff);
439: return resource;
440: }
441:
442: /* ignores context */
443: public boolean hasReifications(Statement statement) {
444: return this .sparqlAsk("ASK WHERE { " + " ?res "
445: + RDF.type.toSPARQL() + " " + RDF.Statement + " ."
446: + " ?res " + RDF.subject.toSPARQL() + " "
447: + statement.getSubject().toSPARQL() + " ." + " ?res "
448: + RDF.predicate.toSPARQL() + " "
449: + statement.getPredicate().toSPARQL() + " ." + " ?res "
450: + RDF.object.toSPARQL() + " "
451: + statement.getObject().toSPARQL() + " ." + " }");
452: }
453:
454: /*
455: * inefficient, loads all in memory. should be OK for almost all practical
456: * cases (when each statement has a small number of refications)
457: *
458: * ignores context
459: */
460: public Collection<Resource> getAllReificationsOf(Statement statement) {
461: QueryResultTable table = this
462: .sparqlSelect("SELECT ?res WHERE { " + " ?res "
463: + RDF.type.toSPARQL() + " " + RDF.Statement
464: + " ." + " ?res " + RDF.subject.toSPARQL()
465: + " " + statement.getSubject().toSPARQL()
466: + " ." + " ?res " + RDF.predicate.toSPARQL()
467: + " " + statement.getPredicate().toSPARQL()
468: + " ." + " ?res " + RDF.object.toSPARQL() + " "
469: + statement.getObject().toSPARQL() + " ."
470: + " }");
471: LinkedList<Resource> result = new LinkedList<Resource>();
472: ClosableIterator<QueryRow> it = table.iterator();
473: while (it.hasNext()) {
474: Resource res = it.next().getValue("res").asResource();
475: result.add(res);
476: }
477: it.close();
478: return result;
479: }
480:
481: /* delete in ALL contexts */
482: public void deleteReification(Resource reificationResource) {
483: Diff diff = new DiffImpl();
484: diff.removeStatement(reificationResource, RDF.type,
485: RDF.Statement);
486: ClosableIterator<Statement> it = findStatements(Variable.ANY,
487: reificationResource, RDF.subject, Variable.ANY);
488: while (it.hasNext()) {
489: diff.removeStatement(it.next());
490: }
491: it.close();
492: it = findStatements(Variable.ANY, reificationResource,
493: RDF.predicate, Variable.ANY);
494: while (it.hasNext()) {
495: diff.removeStatement(it.next());
496: }
497: it.close();
498: it = findStatements(Variable.ANY, reificationResource,
499: RDF.object, Variable.ANY);
500: while (it.hasNext()) {
501: diff.removeStatement(it.next());
502: }
503: it.close();
504: update(diff);
505: }
506:
507: }
|